Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type GUIDs to partitions resolver #2745

Merged
merged 3 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
53 changes: 37 additions & 16 deletions lib/facter/resolvers/partitions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ def populate_partitions(partition_name, block_path, blkid_and_lsblk, backing_fil
size: Facter::Util::Facts::UnitConverter.bytes_to_human_readable(size_bytes),
backing_file: backing_file }
info_hash.merge!(populate_from_syscalls(partition_name, blkid_and_lsblk))
@fact_list[:partitions][partition_name] = info_hash.reject { |_key, value| value.nil? }
@fact_list[:partitions][partition_name] = info_hash.compact
end

def populate_from_syscalls(partition_name, blkid_and_lsblk)
part_info = populate_from_blkid(partition_name, blkid_and_lsblk)
# Prefer lsblk over blkid since lsblk does not require root, returns more information, and is recommended by blkid
part_info = populate_from_lsblk(partition_name, blkid_and_lsblk)

return populate_from_lsblk(partition_name, blkid_and_lsblk) if part_info.empty?
return populate_from_blkid(partition_name, blkid_and_lsblk) if part_info.empty?

part_info
end
Expand Down Expand Up @@ -121,26 +122,46 @@ def execute_and_extract_blkid_info
def populate_from_lsblk(partition_name, blkid_and_lsblk)
return {} unless available?('lsblk', blkid_and_lsblk)

blkid_and_lsblk[:lsblk] ||= Facter::Core::Execution.execute('lsblk -fp', logger: log)
lsblk_version_raw = Facter::Core::Execution.execute('lsblk --version 2>&1', logger: log)
lsblk_version = lsblk_version_raw.match(/ \d\.\d+/)[0].to_f

part_info = blkid_and_lsblk[:lsblk].match(/#{partition_name}.*/).to_s.split(' ')
return {} if part_info.empty?
# The -p/--paths option was added in lsblk 2.23, return early and fall back to blkid with earlier versions
return {} if lsblk_version < 2.23

parse_part_info(part_info)
end
blkid_and_lsblk[:lsblk] ||= execute_and_extract_lsblk_info(lsblk_version)

def parse_part_info(part_info)
result = { filesystem: part_info[1] }
partition_data = blkid_and_lsblk[:lsblk][partition_name]
return {} unless partition_data

if part_info.count.eql?(5)
result[:label] = part_info[2]
result[:uuid] = part_info[3]
else
result[:uuid] = part_info[2]
end
filesys = partition_data['FSTYPE']
uuid = partition_data['UUID']
label = partition_data['LABEL']
part_uuid = partition_data['PARTUUID']
part_label = partition_data['PARTLABEL']
part_type = partition_data['PARTTYPE']

result = { filesystem: filesys, uuid: uuid, label: label, partuuid: part_uuid, partlabel: part_label }
result[:parttype] = part_type if part_type

result
end

def execute_and_extract_lsblk_info(lsblk_version)
# lsblk 2.25 added support for GPT partition type GUIDs
stdout = if lsblk_version >= 2.25
Facter::Core::Execution.execute('lsblk -p -P -o NAME,FSTYPE,UUID,LABEL,PARTUUID,PARTLABEL,PARTTYPE', logger: log)
else
Facter::Core::Execution.execute('lsblk -p -P -o NAME,FSTYPE,LABEL,UUID,PARTUUID,PARTLABEL', logger: log)
end

output_hash = Hash[*stdout.split(/^(NAME=\S+)/)[1..-1]]
output_hash.transform_keys! { |key| key.delete('NAME=')[1..-2] }
output_hash.each do |key, value|
output_hash[key] = Hash[*value.chomp.rstrip.split(/ ([^= ]+)=/)[1..-1].each { |x| x.delete!('"') }]
end
output_hash.each_value { |value_hash| value_hash.delete_if { |_k, v| v.empty? } }
output_hash.delete_if { |_k, v| v.empty? }
end
end
end
end
Expand Down
3 changes: 3 additions & 0 deletions lib/schema/facter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,9 @@ partitions:
backing_file:
type: string
description: The path to the file backing the partition.
parttype:
type: string
description: The partition type GUID.

path:
type: string
Expand Down
46 changes: 43 additions & 3 deletions spec/facter/resolvers/partitions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
allow(Facter::Core::Execution).to receive(:which)
.with('lsblk').and_return('/usr/bin/lsblk')
allow(Facter::Core::Execution).to receive(:execute)
.with('lsblk -fp', logger: an_instance_of(Facter::Log)).and_return(load_fixture('lsblk_output').read)
.with('lsblk --version 2>&1', logger: an_instance_of(Facter::Log)).and_return('lsblk from util-linux 2.24')
allow(Facter::Core::Execution).to receive(:execute)
.with('lsblk -p -P -o NAME,FSTYPE,LABEL,UUID,PARTUUID,PARTLABEL', logger: an_instance_of(Facter::Log)).and_return(load_fixture('lsblk_output_old').read)
end

context 'when block has a device subdir' do
Expand All @@ -68,12 +70,12 @@
context 'when there is more than one partition' do
it 'checks for blkid only once' do
resolver.resolve(:partitions)
expect(Facter::Core::Execution).to have_received(:which).with('blkid').once
expect(Facter::Core::Execution).to have_received(:which).with('blkid').at_most(:once)
end

it 'checks for lsblk only once' do
resolver.resolve(:partitions)
expect(Facter::Core::Execution).to have_received(:which).with('lsblk').once
expect(Facter::Core::Execution).to have_received(:which).with('lsblk').at_most(:once)
end
end

Expand Down Expand Up @@ -189,5 +191,43 @@
end
end
end

context 'when lsblk can read partition types' do
let(:partitions) do
{ '/dev/sda1' => { filesystem: 'ext3', label: '/boot', parttype: '21686148-6449-6E6F-744E-656564454649', size: '117.00 KiB',
size_bytes: 119_808, uuid: '88077904-4fd4-476f-9af2-0f7a806ca25e',
partuuid: '00061fe0-01' },
'/dev/sda2' => { filesystem: 'LVM2_member', parttype: '0fc63daf-8483-4772-8e79-3d69d8477de4', size: '98.25 MiB',
size_bytes: 103_021_056, uuid: 'edi7s0-2WVa-ZBan' } }
end

let(:sda_subdirs) do
['/sys/block/sda/queue',
'/sys/block/sda/sda2',
'/sys/block/sda/sda2/stat',
'/sys/block/sda/sda2/dev',
'/sys/block/sda/sda2/uevent',
'/sys/block/sda/sda1']
end

before do
allow(File).to receive(:directory?).with("#{sys_block_path}/sda/device").and_return(true)
allow(Dir).to receive(:[]).with("#{sys_block_path}/sda/**/*").and_return(sda_subdirs)
sda_subdirs.each { |subdir| allow(File).to receive(:directory?).with(subdir).and_return(true) }
allow(Facter::Util::FileHelper).to receive(:safe_read)
.with("#{sys_block_path}/sda/sda2/size", '0').and_return('201213')
allow(Facter::Util::FileHelper).to receive(:safe_read)
.with("#{sys_block_path}/sda/sda1/size", '0').and_return('234')
end

it 'return partitions fact with part_type' do
allow(Facter::Core::Execution).to receive(:execute)
.with('lsblk --version 2>&1', logger: an_instance_of(Facter::Log)).and_return('lsblk from util-linux 2.25')
allow(Facter::Core::Execution).to receive(:execute)
.with('lsblk -p -P -o NAME,FSTYPE,UUID,LABEL,PARTUUID,PARTLABEL,PARTTYPE', logger: an_instance_of(Facter::Log)).and_return(load_fixture('lsblk_output_new').read)

expect(resolver.resolve(:partitions)).to eq(partitions)
end
end
end
end
7 changes: 0 additions & 7 deletions spec/fixtures/lsblk_output

This file was deleted.

3 changes: 3 additions & 0 deletions spec/fixtures/lsblk_output_new
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NAME="/dev/sda" FSTYPE="" UUID="" LABEL="" PARTUUID="" PARTLABEL="" PARTTYPE=""
NAME="/dev/sda1" FSTYPE="ext3" UUID="88077904-4fd4-476f-9af2-0f7a806ca25e" LABEL="/boot" PARTUUID="00061fe0-01" PARTLABEL="" PARTTYPE="21686148-6449-6E6F-744E-656564454649"
NAME="/dev/sda2" FSTYPE="LVM2_member" UUID="edi7s0-2WVa-ZBan" LABEL="" PARTUUID="" PARTLABEL="" PARTTYPE="0fc63daf-8483-4772-8e79-3d69d8477de4"
3 changes: 3 additions & 0 deletions spec/fixtures/lsblk_output_old
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NAME="/dev/sda" FSTYPE="" UUID="" LABEL="" PARTUUID="" PARTLABEL="" PARTTYPE=""
NAME="/dev/sda1" FSTYPE="ext3" UUID="88077904-4fd4-476f-9af2-0f7a806ca25e" LABEL="/boot" PARTUUID="00061fe0-01" PARTLABEL=""
NAME="/dev/sda2" FSTYPE="LVM2_member" UUID="edi7s0-2WVa-ZBan" LABEL="" PARTUUID="" PARTLABEL=""