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

Add os.release facts on FreeBSD #485

Merged
merged 4 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions lib/facts/freebsd/os/release.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

module Facts
module Freebsd
module Os
class Release
FACT_NAME = 'os.release'
ALIASES = %w[operatingsystemmajrelease operatingsystemrelease].freeze

def call_the_resolver
installed_userland = Facter::Resolvers::Freebsd::FreebsdVersion.resolve(:installed_userland)

value = build_release_hash_from_version(installed_userland)

[Facter::ResolvedFact.new(FACT_NAME, value),
Facter::ResolvedFact.new(ALIASES.first, value[:major], :legacy),
Facter::ResolvedFact.new(ALIASES.last, installed_userland, :legacy)]
end

private

def build_release_hash_from_version(version_string)
version, branch_value = version_string.split('-', 2)
major_value, minor_value = version.split('.')
patchlevel_value = branch_value.split('-p')[1]
smortex marked this conversation as resolved.
Show resolved Hide resolved

value = {
full: version_string,
major: major_value,
branch: branch_value
}

value[:minor] = minor_value if minor_value
value[:patchlevel] = patchlevel_value if patchlevel_value

value
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/framework/detector/os_detector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def detect
:macosx
when /linux/
detect_distro
when /freebsd/
:freebsd
when /bsd/
:bsd
when /solaris/
Expand Down
36 changes: 36 additions & 0 deletions lib/resolvers/freebsd/freebsd_version_resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

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

class << self
private

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

def freebsd_version_system_call(fact_name)
output, _status = Open3.capture2('/bin/freebsd-version -kru')
smortex marked this conversation as resolved.
Show resolved Hide resolved

build_fact_list(output)

@fact_list[fact_name]
end

def build_fact_list(output)
freebsd_version_results = output.split("\n")

@fact_list[:installed_kernel] = freebsd_version_results[0].strip
@fact_list[:running_kernel] = freebsd_version_results[1].strip
@fact_list[:installed_userland] = freebsd_version_results[2].strip
Comment on lines +31 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.strip will raise NoMethodError if output is empty string or if freebsd_version_results[0/1/2] is nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

freebsd-version -kru is expected to return exactly 3 lines (each flag produce a line), so I do not thing this is a problem for us here. Yet, some FreeBSD forks might be detected as "FreeBSD" while not providing freebsd-update, so it's worth being sure that the command succeeded.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HardenedBSD doesn't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igalic did you have the opportunity to try it on HardenedBSD? I need to allocate some time to dig in this project…

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately, my current priority
canonical/cloud-init#363 is a few yak stacks away from testing HardenedBSD

end
end
end
end
end
end
6 changes: 5 additions & 1 deletion os_hierarchy.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
},
{
"Solaris": [
"Bsd"
{
"Bsd": [
"Freebsd"
]
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FreeBSD is definitively a descendant of BSD, yet BSD is not a decedent of Solaris (amusingly, early version of Sun OS (which became Solaris at some point) was based on BSD).

For now, this is convenient because Solaris facts and resolvers provide ZFS related facts which are working on FreeBSD, however, ZFS on Linux is a thing and some refactoring will be necessary at some point. Don't know how / where to log this so that it can be tracked…

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And maybe it is as simple as renaming the Solaris ZFS resolver to make it obvious it is not Solaris specific and use similar facts for FreeBSD, Solaris and maybe Linux to gather these facts… So basically the same code facts multiple times, but maybe it's not a problem?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smortex I talked with @oanatmaria and maybe we can have something like

...
  {
    "Unix": [
      "Solaris",
      {
        "Bsd": [
          "Freebsd"
        ]
      }

    ]
  },
...

Both Solaris and Bsd will inherit from Unix. This is based on the diagram from https://upload.wikimedia.org/wikipedia/commons/7/77/Unix_history-simple.svg

]
},
"Macosx",
Expand Down
71 changes: 71 additions & 0 deletions spec/facter/facts/freebsd/os/release_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

describe Facts::Freebsd::Os::Release do
describe '#call_the_resolver' do
subject(:fact) { Facts::Freebsd::Os::Release.new }

before do
allow(Facter::Resolvers::Freebsd::FreebsdVersion).to receive(:resolve).with(:installed_userland).and_return(value)
end

context 'when FreeBSD RELEASE' do
let(:value) { '12.1-RELEASE-p3' }

it 'calls Facter::Resolvers::Freebsd::FreebsdVersion' do
fact.call_the_resolver
expect(Facter::Resolvers::Freebsd::FreebsdVersion).to have_received(:resolve).with(:installed_userland)
end

it 'returns release fact' do
expect(fact.call_the_resolver).to be_an_instance_of(Array).and \
contain_exactly(an_object_having_attributes(name: 'os.release', value: { 'full' => value,
'major' => '12',
'minor' => '1',
'branch' => 'RELEASE-p3',
'patchlevel' => '3' }),
an_object_having_attributes(name: 'operatingsystemmajrelease', value: '12',
type: :legacy),
an_object_having_attributes(name: 'operatingsystemrelease', value: value, type: :legacy))
end
end

context 'when FreeBSD STABLE' do
let(:value) { '12.1-STABLE' }

it 'calls Facter::Resolvers::Freebsd::FreebsdVersion' do
fact.call_the_resolver
expect(Facter::Resolvers::Freebsd::FreebsdVersion).to have_received(:resolve).with(:installed_userland)
end

it 'returns release fact' do
expect(fact.call_the_resolver).to be_an_instance_of(Array).and \
contain_exactly(an_object_having_attributes(name: 'os.release', value: { 'full' => value,
'major' => '12',
'minor' => '1',
'branch' => 'STABLE' }),
an_object_having_attributes(name: 'operatingsystemmajrelease', value: '12',
type: :legacy),
an_object_having_attributes(name: 'operatingsystemrelease', value: value, type: :legacy))
end
end

context 'when FreeBSD CURRENT' do
let(:value) { '13-CURRENT' }

it 'calls Facter::Resolvers::Freebsd::FreebsdVersion' do
fact.call_the_resolver
expect(Facter::Resolvers::Freebsd::FreebsdVersion).to have_received(:resolve).with(:installed_userland)
end

it 'returns release fact' do
expect(fact.call_the_resolver).to be_an_instance_of(Array).and \
contain_exactly(an_object_having_attributes(name: 'os.release', value: { 'full' => value,
'major' => '13',
'branch' => 'CURRENT' }),
an_object_having_attributes(name: 'operatingsystemmajrelease', value: '13',
type: :legacy),
an_object_having_attributes(name: 'operatingsystemrelease', value: value, type: :legacy))
end
end
end
end
29 changes: 29 additions & 0 deletions spec/facter/resolvers/freebsd/freebsd_version_resolver_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

describe Facter::Resolvers::Freebsd::FreebsdVersion do
before do
allow(Open3).to receive(:capture2)
.with('/bin/freebsd-version -kru')
.and_return('13.0-CURRENT
12.1-RELEASE-p3
12.0-STABLE')
end

it 'returns installed kernel' do
result = Facter::Resolvers::Freebsd::FreebsdVersion.resolve(:installed_kernel)

expect(result).to eq('13.0-CURRENT')
end

it 'returns running kernel' do
result = Facter::Resolvers::Freebsd::FreebsdVersion.resolve(:running_kernel)

expect(result).to eq('12.1-RELEASE-p3')
end

it 'returns installed userland' do
result = Facter::Resolvers::Freebsd::FreebsdVersion.resolve(:installed_userland)

expect(result).to eq('12.0-STABLE')
end
end