# # partitions.rb # BY kwilczynski (https://github.com/kwilczynski/facter-facts/blob/master/partitions.rb) # This fact provides an alphabetic list of blocks per disk and/or partition, # partitions per disk and disks. # # We support most of generic SATA and PATA disks, plus Hewlett-Packard # Smart Array naming format ... This also should work for systems running # as Virtual Machine guest at least for Xen and KVM ... # if Facter.value(:kernel) == 'Linux' # We store a list of disks (or block devices if you wish) here ... disks = [] # We store number of blocks per disk and/or partition here ... blocks = {} # We store a list of partitions on per-disk basis here ... partitions = Hash.new { |k,v| k[v] = [] } # # Support for the following might not be of interest ... # # MMC is Multi Media Card which can be either SD or microSD, etc ... # MTD is Memory Technology Device also known as Flash Memory # exclude = %w(backdev.* dm-\d loop mmcblk mtdblock ram ramzswap) # # Modern Linux kernels provide "/proc/partitions" in the following format: # # major minor #blocks name # # 8 0 244198584 sda # 8 1 3148708 sda1 # 8 2 123804922 sda2 # 8 3 116214210 sda3 # 8 4 1028160 sda4 # # Make regular expression form our patterns ... exclude = Regexp.union(*exclude.collect { |i| Regexp.new(i) }) # # We utilise rely on "cat" for reading values from entries under "/proc". # This is due to some problems with IO#read in Ruby and reading content of # the "proc" file system that was reported more than once in the past ... # Facter::Util::Resolution.exec('cat /proc/partitions 2> /dev/null').each_line do |line| # Remove bloat ... line.strip! # Line of interest should start with a number ... next if line.empty? or line.match(/^[a-zA-Z]+/) # We have something, so let us apply our device type filter ... next if line.match(exclude) # Only blocks and partitions matter ... block = line.split(/\s+/)[2] partition = line.split(/\s+/)[3] if partition.match(/^cciss/) # # Special case for Hewlett-Packard Smart Array which probably # nobody is using any more nowadays anyway ... # partition = partition.split('/')[1] if match = partition.match(/^([a-zA-Z0-9]+)[pP][0-9]+/) # Handle the case when "cciss/c0d0p1" is given ... disk = match[1] elsif partition.match(/^[a-zA-Z0-9]+/) # Handle the case when "cciss/c0d0" is given ... disk = partition end else # Take care of any partitions create atop of the # Linux Software RAID decies like e.g. /dev/md0, etc. if match = partition.match(/^(md\d+)/) disk = match[1] else # Everything else ... disk = partition.scan(/^[a-zA-Z]+/) end end # Convert back into a string value ... disk = Array(disk).first.to_s # We have something rather odd that did not parse at all, so ignore ... next if disk.empty? # All disks ... This might even be sda, sdaa, sdab, sdac, etc ... disks << disk # Store details about number of blocks per disk and/or partition ... blocks[partition] = block # A disk is not a partition, therefore we ignore ... partitions[disk] << partition unless partition == disk end Facter.add('disks') do confine :kernel => :linux setcode { disks.sort.uniq.join(',') } end blocks.each do |k,v| Facter.add("blocks_#{k}") do confine :kernel => :linux setcode { v } end end partitions.each do |k,v| Facter.add("partitions_#{k}") do confine :kernel => :linux # To ensure proper sorting order by the interface name ... v = v.sort_by { |i| i.scan(/\d+/).shift.to_i } setcode { v.sort.join(',') } end end end