class LinuxAdmin::Disk
Constants
- PARTED_FIELDS
Attributes
model[RW]
path[RW]
Public Class Methods
local()
click to toggle source
Collect local disk information via the lsblk command. Only disks with a size greater than zero are returned.
# File lib/linux_admin/disk.rb, line 14 def self.local result = Common.run!(Common.cmd("lsblk"), :params => {:b => nil, :d => nil, :n => nil, :p => nil, :o => "NAME,SIZE,TYPE,MODEL"}) result.output.split("\n").collect do |string| path, size, type, *model = string.split if type.casecmp?('disk') && size.to_i > 0 self.new(:path => path, :size => size.to_i, :model => model.join(' ')) end end.compact end
new(args = {})
click to toggle source
# File lib/linux_admin/disk.rb, line 24 def initialize(args = {}) @path = args[:path] @model = args[:model] || "unknown" @size = args[:size] end
Public Instance Methods
clear!()
click to toggle source
# File lib/linux_admin/disk.rb, line 101 def clear! @partitions = [] # clear partition table Common.run!(Common.cmd(:dd), :params => { 'if=' => '/dev/zero', 'of=' => @path, 'bs=' => 512, 'count=' => 1}) self end
create_partition(partition_type, *args)
click to toggle source
# File lib/linux_admin/disk.rb, line 61 def create_partition(partition_type, *args) create_partition_table unless has_partition_table? start = finish = size = nil case args.length when 1 then start = partitions.empty? ? 0 : partitions.last.end_sector size = args.first finish = start + size when 2 then start = args[0] finish = args[1] else raise ArgumentError, "must specify start/finish or size" end id = partitions.empty? ? 1 : (partitions.last.id + 1) options = parted_options_array('mkpart', '-a', 'opt', partition_type, start, finish) Common.run!(Common.cmd(:parted), :params => {nil => options}) partition = Partition.new(:disk => self, :id => id, :start_sector => start, :end_sector => finish, :size => size, :partition_type => partition_type) partitions << partition partition end
create_partition_table(type = "msdos")
click to toggle source
# File lib/linux_admin/disk.rb, line 51 def create_partition_table(type = "msdos") Common.run!(Common.cmd(:parted), :params => {nil => parted_options_array("mklabel", type)}) end
create_partitions(partition_type, *args)
click to toggle source
# File lib/linux_admin/disk.rb, line 93 def create_partitions(partition_type, *args) check_if_partitions_overlap(args) args.each { |arg| self.create_partition(partition_type, arg[:start], arg[:end]) } end
has_partition_table?()
click to toggle source
# File lib/linux_admin/disk.rb, line 55 def has_partition_table? result = Common.run(Common.cmd(:parted), :params => {nil => parted_options_array("print")}) result_indicates_partition_table?(result) end
partition_path(id)
click to toggle source
# File lib/linux_admin/disk.rb, line 112 def partition_path(id) case model when "nvme" "#{path}p#{id}" else "#{path}#{id}" end end
partitions()
click to toggle source
# File lib/linux_admin/disk.rb, line 44 def partitions @partitions ||= parted_output.collect { |disk| partition_from_parted(disk) } end
size()
click to toggle source
# File lib/linux_admin/disk.rb, line 30 def size @size ||= begin size = nil out = Common.run!(Common.cmd(:fdisk), :params => {"-l" => nil}).output out.each_line do |l| /Disk #{path}: .*B, (\d+) bytes/.match(l) do |m| size = m[1].to_i break end end size end end
Private Instance Methods
check_if_partitions_overlap(partitions)
click to toggle source
# File lib/linux_admin/disk.rb, line 147 def check_if_partitions_overlap(partitions) ranges = partitions.collect do |partition| start = partition[:start] finish = partition[:end] start.delete('%') finish.delete('%') start.to_f..finish.to_f end if overlapping_ranges?(ranges) raise ArgumentError, "overlapping partitions" end end
overlapping_ranges?(ranges)
click to toggle source
# File lib/linux_admin/disk.rb, line 134 def overlapping_ranges?(ranges) ranges.find do |range1| ranges.any? do |range2| range1 != range2 && ranges_overlap?(range1, range2) end end end
parse_model(parted_line)
click to toggle source
# File lib/linux_admin/disk.rb, line 179 def parse_model(parted_line) matches = parted_line.match(/^Model:.*\((?<model>\w+)\)$/) @model = matches[:model] if matches end
parted_default_options()
click to toggle source
# File lib/linux_admin/disk.rb, line 209 def parted_default_options @parted_default_options ||= ['--script', path].freeze end
parted_options_array(*args)
click to toggle source
# File lib/linux_admin/disk.rb, line 204 def parted_options_array(*args) args = args.first if args.first.kind_of?(Array) parted_default_options + args end
parted_output()
click to toggle source
# File lib/linux_admin/disk.rb, line 162 def parted_output # TODO: Should this really catch non-zero RC, set output to the default "" and silently return [] ? # If so, should other calls to parted also do the same? # requires sudo out = Common.run(Common.cmd(:parted), :params => { nil => parted_options_array('print') }).output split = [] out.each_line do |l| if l =~ /^ [0-9].*/ split << l.split elsif l =~ /^Model:.*/ parse_model(l) end end split end
partition_from_parted(output_disk)
click to toggle source
# File lib/linux_admin/disk.rb, line 184 def partition_from_parted(output_disk) args = {:disk => self} PARTED_FIELDS.each_index do |i| val = output_disk[i] case PARTED_FIELDS[i] when :start_sector, :end_sector, :size if val =~ /([0-9\.]*)([kKMG])B/ val = str_to_bytes($1, $2) end when :id val = val.to_i end args[PARTED_FIELDS[i]] = val end Partition.new(args) end
ranges_overlap?(range1, range2)
click to toggle source
# File lib/linux_admin/disk.rb, line 143 def ranges_overlap?(range1, range2) # copied from activesupport Range#overlaps? range1.cover?(range2.first) || range2.cover?(range1.first) end
result_indicates_partition_table?(result)
click to toggle source
# File lib/linux_admin/disk.rb, line 213 def result_indicates_partition_table?(result) # parted exits with 1 but writes this oddly spelled error to stdout. missing = (result.exit_status == 1 && result.output.include?("unrecognised disk label")) !missing end
str_to_bytes(val, unit)
click to toggle source
# File lib/linux_admin/disk.rb, line 123 def str_to_bytes(val, unit) case unit when 'K', 'k' then val.to_f * 1_024 # 1.kilobytes when 'M' then val.to_f * 1_048_576 # 1.megabyte when 'G' then val.to_f * 1_073_741_824 # 1.gigabytes end end