core/rails/lib/barclamp_raid/driver.rb
# Given a volume specification hash, find disks on the controller that are
# good candidates for including in the to-be-created volume.
# This method takes into account the desired size of the volume,
# whether or not this volume can share disks with other volumes,
# the type of disks to use in the volume, whether SAS or SATA volumes
# should be chosen, and it makes sure that all chosen disks are
# of the same time and approximately the same size.
# @param volume [Hash] A hash that contains the salient details of the volume.
#   See {Driver#create_vd} for details on what keys are allowed and what they mean.
# @return [Array<BarclampRaid::RaidDisk>] The disks that should be used to create
#  the volume.
Given a volume specification hash, find disks on the controller that are
good candidates for including in the to-be-created volume.
This method takes into account the desired size of the volume,
whether or not this volume can share disks with other volumes,
the type of disks to use in the volume, whether SAS or SATA volumes
should be chosen, and it makes sure that all chosen disks are
of the same time and approximately the same size.
Given a volume specification hash find disks on the controller that are good candidates for including in the to - be - created volume . This method takes into account the desired size of the volume whether or not this volume can share disks with other volumes the type of disks to use in the volume whether SAS or SATA volumes should be chosen and it makes sure that all chosen disks are of the same time and approximately the same size .
def find_candidates(volume)
      raid_level  = volume["raid_level"]
      disks       = volume["disks"]
      size        = volume["size"] || "max"
      exclusive   = (volume["exclusive"].nil? || size.nil?) ? true : !!volume["exclusive"]
      disk_type   = volume["disk_type"]
      protocol    = volume["protocol"]
      stripe_size = BarclampRaid.size_to_bytes(volume["stripe_size"] || "64 KB")
      disks, spans = BarclampRaid.calc_spans(raid_level,disks)
      min_disks, max_disks, _ = BarclampRaid.calc_raid_overhead(raid_level,spans)
      raise "RAID type #{raid_level} requires at least #{min_disks} disks" unless disks >= min_disks
      raise "RAID type #{raid_level} cannot have more than #{max_disks} disks" unless disks <= max_disks
      candidate_sizes = Hash.new
      candidates = Array.new
      if exclusive
        candidates = self.unused_disks
        candidates.each{|c|candidate_sizes[c.id] = c.disk_size}
      else
        candidates = self.diskscontroller = BarclampRaid::RaidHammer.drivers(Node.find(2))[0].controllers[0]
        candidates.each do |c|
          candidate_sizes[c.id] = c.disk_size
        end
        self.volumes.each do |vol|
          disk_size = vol.size_per_disks
          vol.disks.each do |d|
            candidate_sizes[d.id] -= disk_size
          end
        end
      end
      type_buckets = Hash.new
      candidates.each do |c|
        type_buckets[[c.protocol,c.media_type]] ||= Array.new
        type_buckets[[c.protocol,c.media_type]] << c
      end
      chosen_buckets = Array.new
      (disk_type ? [disk_type] : ["disk","ssd"]).each do |c_mt|
        (protocol ? [protocol] : ["sas","sata"]).each do |c_p|
          selector = [c_p,c_mt]
          next unless type_buckets[selector]
          if type_buckets[selector].length < disks
            Rails.logger.info("#{self.class.name}: Discarding disk type #{selector.inspect} due to insufficient disks")
            next
          end
          chosen_buckets << type_buckets[selector]
          break
        end
      end
      raise "Not enough combinable disks to satisfy volume creation request!" if chosen_buckets.empty?
      res = []
      chosen_buckets.each do |bucket|
        break unless res.empty?
        size_buckets = Hash.new
        bucket.each do |disk|
          size_bucket = candidate_sizes[disk.id] >> 35 << 35
          size_buckets[size_bucket] ||= Array.new
          size_buckets[size_bucket] << disk
        end
        size_candidates = case size
                          when "max" then size_buckets.keys.sort.reverse
                          when "min" then size_buckets.keys.sort
                          else
                            size_per_disk = BarclampRaid.raid_per_disk_size(
                                                                            BarclampRaid.size_to_bytes(size),
                                                                            raid_level,
                                                                            disks,
                                                                            spans,
                                                                            stripe_size)
                            size_buckets.keys.sort.reject{|b| b < (size_per_disk >> 35 << 35)}
                          end
Rails.logger.error("GREG: size_candidates = #{size_candidates.inspect}")
        size_candidates.each do |c|
          next unless size_buckets[c].length >= disks
          res = size_buckets[c]
          break
        end
      end
      if res.empty?
        raise "Not enough compatible disks on controller #{self.name} to build #{volume.inspect}"
      end
      res.sort.take(disks)
    end
def find_candidates ( volume ) raid_level = volume [ "raid_level" ] disks = volume [ "disks" ] size = volume [ "size" ] || "max" exclusive = ( volume [ "exclusive" ] . nil? || size . nil? ) ? true : ! ! volume [ "exclusive" ] disk_type = volume [ "disk_type" ] protocol = volume [ "protocol" ] stripe_size = BarclampRaid . size_to_bytes ( volume [ "stripe_size" ] || "64 KB" ) disks , spans = BarclampRaid . calc_spans ( raid_level , disks ) min_disks , max_disks , _ = BarclampRaid . calc_raid_overhead ( raid_level , spans ) raise "RAID type #{raid_level} requires at least #{min_disks} disks" unless disks >= min_disks raise "RAID type #{raid_level} cannot have more than #{max_disks} disks" unless disks <= max_disks candidate_sizes = Hash . new candidates = Array . new if exclusive candidates = self . unused_disks candidates . each { | c | candidate_sizes [ c . id ] = c . disk_size } else candidates = self . diskscontroller = BarclampRaid :: RaidHammer . drivers ( Node . find ( 2 ) ) [ 0 ] . controllers [ 0 ] candidates . each do | c | candidate_sizes [ c . id ] = c . disk_size end self . volumes . each do | vol | disk_size = vol . size_per_disks vol . disks . each do | d | candidate_sizes [ d . id ] -= disk_size end end end type_buckets = Hash . new candidates . each do | c | type_buckets [ [ c . protocol , c . media_type ] ] ||= Array . new type_buckets [ [ c . protocol , c . media_type ] ] << c end chosen_buckets = Array . new ( disk_type ? [ disk_type ] : [ "disk" , "ssd" ] ) . each do | c_mt | ( protocol ? [ protocol ] : [ "sas" , "sata" ] ) . each do | c_p | selector = [ c_p , c_mt ] next unless type_buckets [ selector ] if type_buckets [ selector ] . length < disks Rails . logger . info ( "#{self.class.name}: Discarding disk type #{selector.inspect} due to insufficient disks" ) next end chosen_buckets << type_buckets [ selector ] break end end raise "Not enough combinable disks to satisfy volume creation request!" if chosen_buckets . empty? res = [ ] chosen_buckets . each do | bucket | break unless res . empty? size_buckets = Hash . new bucket . each do | disk | size_bucket = candidate_sizes [ disk . id ] >> 35 << 35 size_buckets [ size_bucket ] ||= Array . new size_buckets [ size_bucket ] << disk end size_candidates = case size when "max" then size_buckets . keys . sort . reverse when "min" then size_buckets . keys . sort else size_per_disk = BarclampRaid . raid_per_disk_size ( BarclampRaid . size_to_bytes ( size ) , raid_level , disks , spans , stripe_size ) size_buckets . keys . sort . reject { | b | b < ( size_per_disk >> 35 << 35 ) } end Rails . logger . error ( "GREG: size_candidates = #{size_candidates.inspect}" ) size_candidates . each do | c | next unless size_buckets [ c ] . length >= disks res = size_buckets [ c ] break end end if res . empty? raise "Not enough compatible disks on controller #{self.name} to build #{volume.inspect}" end res . sort . take ( disks ) end
Given a volume specification hash, find disks on the controller that are
good candidates for including in the to-be-created volume.
Given a volume specification hash find disks on the controller that are good candidates for including in the to - be - created volume .
# Only look at disks that do not have any RAID volumes on them. # Look at all the disks, and figure out how much free space each drive has. # Bucketize candidates according to disk_type and protocol. Most RAID controllers # rewuire that the drives be fairly homogenous, so we enforce that all of the disks # in our prospective RAID volume talk the same protocol and are the same media type. # Bucketize the disks in each chosen bucket by size.  Base the sizes # on candidate_sizes, rounded down to the nearest 32 gigabytes. # This is hardly a perfect heuristic, but it should work well enough. # Now we have the candidates sorted in the order we should grab disks from. # Grab the disks we should use, sorted in ascending order by disk ID.
The disks that should be used to create the volume.
The disks that should be used to create the volume .
Array<BarclampRaid::RaidDisk>
volume
A hash that contains the salient details of the volume. See {Driver#create_vd} for details on what keys are allowed and what they mean.
A hash that contains the salient details of the volume . See { Driver#create_vd } for details on what keys are allowed and what they mean .