wavesoftware/puppet-xtreemfs

View on GitHub
lib/puppet/provider/xtreemfs_replicate/xtfsutil.rb

Summary

Maintainability
A
1 hr
Test Coverage
require File.join(File.dirname(__FILE__), '../../../puppet_x/wavesoftware/xtreemfs/provider/xtfsutil')

# A puppet provider for type :xtreemfs_replicate
Puppet::Type.type(:xtreemfs_replicate).provide(:xtfsutil, 
  :parent => Puppet_X::Wavesoftware::Xtreemfs::Provider::Xtfsutil) do

  desc "Manages xtreemfs_replicate of a files of mounted XtreemFS filesystem"

  commands :xtfsutil => 'xtfsutil'

  # Loads an raw data for file
  #
  # @param file [String] a file name
  # @return [Hash] a raw data hash
  def self.prefetch_one file
    output = xtfsutil_cmd file
    propss, replicass = output.split(/Replicas:/)
    re = /(.+)\s{2,}(.+)/
    props = {}
    propss.split("\n").each do |line|
      m = re.match line
      key = m[1].strip
      value = m[2].strip
      props[key] = value
    end
    re = /\s+Striping policy\s+(.+?)\s+\/\s+(.+?)\s+\/\s+(.+?)\n\s+OSD\s+([0-9]+)\s+([a-fA-F0-9-]+)\s+\((.+)\)/m
    replicas = []
    replicass.split(/\s*Replica\s+[0-9]+\n/)[1..-1].each do |line|
      all, strip, strip_n, strip_size, osd, uuid, address = re.match(line).to_a
      props['Striping'] = strip
      props['Striping count'] = strip_n
      props['Striping size'] = strip_size
      replicas << {
        :strip       => strip,
        :strip_n     => strip_n,
        :strip_size  => strip_size,
        :osd         => osd,
        :osd_uuid    => uuid,
        :osd_address => address
      }
    end
    props['Replicas'] = replicas
    return props
  end

  # Loads an provider with data for file
  #
  # @param file [String] a file name
  # @return [Puppet::Type::Xtreemfs_replicate::Xtfsutil]
  def self.load_provider file
    unless File.file? file
      return nil
    end
    props = prefetch_one file
    provider = new(
      :file   => file,
      :policy => correct_policy(props['Replication policy']).to_sym,
      :factor => props['Replicas'].size
    )
    provider.rawprops = props
    return provider
  end

  # Validates if target file can be used as a target for xtfsutil commandline tool
  #
  # @return [nil]
  def validate
    unless File.exists? resource[:file]
      fail "A file for replicate must exists, but it doesn't - #{resource[:file]}"
    end
    unless File.file? resource[:file]
      type = File.stat(resource[:file]).ftype
      fail "A file for replicate must be regular file, but #{type} given - #{resource[:file]}"
    end
    nil
  end

  # Actually sets a policy to the OS
  #
  # @return [String] a command output
  def set_policy
    xtfsutil ['--set-replication-policy', @property_flush[:policy], resource[:file]]
  end

  # Ensures that target file has no replicas
  #
  # @return [nil]
  def unreplicate
    shuffled = @rawprops['Replicas'].shuffle[1..-1]
    shuffled.each do |repl|
      xtfsutil ['--delete-replica', repl[:osd_uuid], resource[:file]]
      @property_hash[:factor] -= 1
    end
    @rawprops['Replicas'].reject { |el| shuffled.include? el }
    @property_flush[:factor] = resource[:factor]
    return nil
  end

  # Ensures that target file has so many replicas to match :factor property
  #
  # @return [nil]
  def replicate
    count = (@property_flush[:factor] - factor())
    osds = available_osds resource[:file]
    if count > osds.size
      possible = osds.size + @property_hash[:factor]
      Puppet.warning "There is not enough available OSD servers to adjust replication" +
        " factor to: #{@property_flush[:factor]}. Setting replication factor to highest" +
        " possible value: #{possible}"
      count = osds.size
    end
    count.times do 
      xtfsutil ['--add-replica', 'auto', resource[:file]]
      @property_hash[:factor] += 1
    end
    return nil
  end

  # Gets available osds for given file
  #
  # @return [Array] a list of available OSD servers that can be used to replicate given file
  def available_osds file
    re = /\s+([a-fA-F0-9-]+)\s+\((.+)\)/
    osds = xtfsutil(['--list-osds', resource[:file]]).split("\n")[1..-1]
    osds.collect do |line|
      all, uuid, address = re.match(line).to_a
      {
        :uuid    => uuid,
        :address => address
      }
    end
  end

end