ManageIQ/manageiq-smartstate

View on GitHub
lib/MiqVm/MiqVm.rb

Summary

Maintainability
C
1 day
Test Coverage
F
47%
require 'ostruct'
require 'metadata/VmConfig/VmConfig'
require 'disk/MiqDisk'
require 'VolumeManager/MiqVolumeManager'
require 'fs/MiqMountManager'
require 'metadata/MIQExtract/MIQExtract'

class MiqVm
  attr_reader :vmConfig, :vmConfigFile, :vim, :vimVm, :rhevm, :rhevmVm, :diskInitErrors, :wholeDisks

  def initialize(vmCfg, ost = nil)
    @ost = ost || OpenStruct.new
    $log.debug "MiqVm::initialize: @ost = nil" if $log && !@ost
    @vmDisks = nil
    @wholeDisks = []
    @rootTrees = nil
    @volumeManager = nil
    @applianceVolumeManager = nil
    @vmConfigFile = ""
    @diskInitErrors = {}
    unless vmCfg.kind_of?(Hash)
      @vmConfigFile = vmCfg
      @vmDir = File.dirname(vmCfg)
    end

    $log.debug "MiqVm::initialize: @ost.openParent = #{@ost.openParent}" if $log

    #
    # If we're passed an MiqVim object, then use VIM to obtain the Vm's
    # configuration through the instantiated server.
    # If we're passed a snapshot ID, then obtain the configration of the
    # VM when the snapshot was taken.
    #
    # TODO: move to MiqVmwareVm
    if (@vim = @ost.miqVim)
      $log.debug "MiqVm::initialize: accessing VM through server: #{@vim.server}" if $log.debug?
      @vimVm = @vim.getVimVm(vmCfg)
      $log.debug "MiqVm::initialize: setting @ost.miqVimVm = #{@vimVm.class}" if $log.debug?
      @ost.miqVimVm = @vimVm
      @vmConfig = VmConfig.new(@vimVm.getCfg(@ost.snapId))
    # TODO: move this to MiqRhevmVm.
    elsif (@rhevm = @ost.miqRhevm)
      $log.debug "MiqVm::initialize: accessing VM through RHEVM server" if $log.debug?
      $log.debug "MiqVm::initialize: vmCfg = #{vmCfg}"
      @rhevmVm = @rhevm.vm_or_template_by_path(vmCfg)
      $log.debug "MiqVm::initialize: setting @ost.miqRhevmVm = #{@rhevmVm.class}" if $log.debug?
      @ost.miqRhevmVm = @rhevmVm
      @vmConfig = VmConfig.new(getCfg(@ost.snapId))
      $log.debug "MiqVm::initialize: @vmConfig.getHash = #{@vmConfig.getHash.inspect}"
      $log.debug "MiqVm::initialize: @vmConfig.getDiskFileHash = #{@vmConfig.getDiskFileHash.inspect}"
    else
      @vimVm = nil
      @vmConfig = VmConfig.new(vmCfg)
    end
  end # def initialize

  def vmDisks
    @vmDisks ||= begin
      @volMgrPS = VolMgrPlatformSupport.new(@vmConfig.configFile, @ost)
      @volMgrPS.preMount

      openDisks(@vmConfig.getDiskFileHash)
    end
  end

  def openDisks(diskFiles)
    pVolumes = []

    $log.debug "openDisks: no disk files supplied." unless diskFiles

    #
    # Build a list of the VM's physical volumes.
    #
    diskFiles.each do |dtag, df|
      $log.debug "openDisks: processing disk file (#{dtag}): #{df}"
      dInfo = OpenStruct.new

      if @ost.miqVim
        dInfo.vixDiskInfo            = {}
        dInfo.vixDiskInfo[:fileName] = @ost.miqVim.datastorePath(df)
        if @ost.miqVimVm
          @vdlConnection = @ost.miqVimVm.vdlVcConnection unless @vdlConnection
        else
          @vdlConnection = @ost.miqVim.vdlConnection unless @vdlConnection
        end
        $log.debug "openDisks: using disk file path: #{dInfo.vixDiskInfo[:fileName]}"
        dInfo.vixDiskInfo[:connection]  = @vdlConnection
      else
        dInfo.fileName = df
        disk_format = @vmConfig.getHash["#{dtag}.format"]  # Set by rhevm for iscsi and fcp disks
        dInfo.format = disk_format unless disk_format.blank?
      end

      mode = @vmConfig.getHash["#{dtag}.mode"]

      dInfo.hardwareId = dtag
      dInfo.baseOnly = @ost.openParent unless mode && mode["independent"]
      dInfo.rawDisk = @ost.rawDisk
      $log.debug "MiqVm::openDisks: dInfo.baseOnly = #{dInfo.baseOnly}"

      begin
        d = applianceVolumeManager && applianceVolumeManager.lvHash[dInfo.fileName] if @rhevm
        if d
          $log.debug "MiqVm::openDisks: using applianceVolumeManager for #{dInfo.fileName}" if $log.debug?
          d.dInfo.fileName = dInfo.fileName
          d.dInfo.hardwareId = dInfo.hardwareId
          d.dInfo.baseOnly = dInfo.baseOnly
          d.dInfo.format = dInfo.format if dInfo.format
          d.dInfo.applianceVolumeManager = applianceVolumeManager
          #
          # Here, we need to probe the disk to determine its data format,
          # QCOW for example. If the disk format is not flat, push a disk
          # supporting the format on top of this disk. Then set d to point
          # to the new top disk.
          #
          d = d.pushFormatSupport
        else
          d = MiqDisk.getDisk(dInfo)
          # I am not sure if getting a nil handle back should throw an error or not.
          # For now I am just skipping to the next disk.  (GMM)
          next if d.nil?
        end
      rescue => err
        $log.error "Couldn't open disk file: #{df}"
        $log.error err.to_s
        $log.debug err.backtrace.join("\n")
        @diskInitErrors[df] = err.to_s
        next
      end

      @wholeDisks << d
      p = d.getPartitions
      if p.empty?
        #
        # If the disk has no partitions, the whole disk can be a single volume.
        #
        pVolumes << d
      else
        #
        # If the disk is partitioned, the partitions are physical volumes,
        # but not the whild disk.
        #
        pVolumes.concat(p)
      end
    end

    pVolumes
  end # def openDisks

  def rootTrees
    return @rootTrees if @rootTrees
    @rootTrees = MiqMountManager.mountVolumes(volumeManager, @vmConfig, @ost)
    volumeManager.rootTrees = @rootTrees
    @rootTrees
  end

  def volumeManager
    @volumeManager ||= MiqVolumeManager.new(vmDisks)
  end

  def applianceVolumeManager
    return nil if @ost.nfs_storage_mounted
    @applianceVolumeManager ||= MiqVolumeManager.fromNativePvs
  end

  def snapshots(refresh = false)
    return nil unless @vimVm
    return @vimVm.snapshotInfo(refresh) if @vimVm
  end

  def unmount
    $log.info "MiqVm.unmount called."
    @wholeDisks.each(&:close)
    @wholeDisks.clear
    if @volumeManager
      @volumeManager.close
      @volumeManager = nil
    end
    @applianceVolumeManager.closeAll if @applianceVolumeManager
    @applianceVolumeManager = nil
    @ost.miqVim.closeVdlConnection(@vdlConnection) if @vdlConnection
    if @volMgrPS
      @volMgrPS.postMount
      @volMgrPS = nil
    end
    @vimVm.release if @vimVm
    @rootTrees = nil
    @vmDisks = nil
  end

  def miq_extract
    @miq_extract ||= MIQExtract.new(self, @ost)
  end

  def extract(c)
    xml = miq_extract.extract(c)
    raise "Could not extract \"#{c}\" from VM" unless xml
    (xml)
  end
end # class MiqVm