@Override
  protected boolean canDoAction() {
    final VM vm = getVm();

    if (vm == null) {
      return failCanDoAction(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
    }

    if (!canRunActionOnNonManagedVm()) {
      return false;
    }

    VmValidator vmValidator = new VmValidator(vm);
    if (!validate(vmValidator.isVmPluggedDiskNotUsingScsiReservation())) {
      return false;
    }

    if (!FeatureSupported.isMigrationSupported(
        getVdsGroup().getArchitecture(), getVdsGroup().getCompatibilityVersion())) {
      return failCanDoAction(EngineMessage.MIGRATION_IS_NOT_SUPPORTED);
    }

    // If VM is pinned to host, no migration can occur
    if (vm.getMigrationSupport() == MigrationSupport.PINNED_TO_HOST) {
      return failCanDoAction(EngineMessage.ACTION_TYPE_FAILED_VM_IS_PINNED_TO_HOST);
    }

    if (vm.getMigrationSupport() == MigrationSupport.IMPLICITLY_NON_MIGRATABLE
        && !getParameters().isForceMigrationForNonMigratableVm()) {
      return failCanDoAction(
          EngineMessage
              .ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE_AND_IS_NOT_FORCED_BY_USER_TO_MIGRATE);
    }

    switch (vm.getStatus()) {
      case MigratingFrom:
        return failCanDoAction(EngineMessage.ACTION_TYPE_FAILED_MIGRATION_IN_PROGRESS);

      case NotResponding:
        return failVmStatusIllegal();

      case Paused:
        if (vm.getVmPauseStatus() == VmPauseStatus.EIO) {
          return failCanDoAction(EngineMessage.MIGRATE_PAUSED_EIO_VM_IS_NOT_SUPPORTED);
        }
        break;

      default:
    }

    if (!vm.isQualifyToMigrate()) {
      return failCanDoAction(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_RUNNING);
    }

    if (!validate(
            vmValidator.vmNotHavingPluggedDiskSnapshots(
                EngineMessage.ACTION_TYPE_FAILED_VM_HAS_PLUGGED_DISK_SNAPSHOT))
        || !validate(vmValidator.vmNotHavingPassthroughVnics())) {
      return false;
    }

    if (getParameters().getTargetVdsGroupId() != null) {
      ChangeVmClusterValidator changeVmClusterValidator =
          new ChangeVmClusterValidator(this, getParameters().getTargetVdsGroupId());
      if (!changeVmClusterValidator.validate()) {
        return false;
      }
    }

    return validate(new SnapshotsValidator().vmNotDuringSnapshot(vm.getId()))
        // This check was added to prevent migration of VM while its disks are being migrated
        // TODO: replace it with a better solution
        && validate(
            new DiskImagesValidator(ImagesHandler.getPluggedActiveImagesForVm(vm.getId()))
                .diskImagesNotLocked())
        && schedulingManager.canSchedule(
            getVdsGroup(),
            getVm(),
            getVdsBlackList(),
            getParameters().getInitialHosts(),
            getDestinationHostList(),
            getReturnValue().getCanDoActionMessages());
  }
  @Override
  protected boolean canDoAction() {
    final VM vm = getVm();

    if (vm == null) {
      return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_FOUND);
    }

    if (!canRunActionOnNonManagedVm()) {
      return false;
    }

    if (!FeatureSupported.isMigrationSupported(
        getVdsGroup().getArchitecture(), getVdsGroup().getcompatibility_version())) {
      return failCanDoAction(VdcBllMessages.MIGRATION_IS_NOT_SUPPORTED);
    }

    // If VM is pinned to host, no migration can occur
    if (vm.getMigrationSupport() == MigrationSupport.PINNED_TO_HOST) {
      return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_PINNED_TO_HOST);
    }

    if (vm.getMigrationSupport() == MigrationSupport.IMPLICITLY_NON_MIGRATABLE
        && !getParameters().isForceMigrationForNonMigratableVm()) {
      return failCanDoAction(
          VdcBllMessages
              .ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE_AND_IS_NOT_FORCED_BY_USER_TO_MIGRATE);
    }

    switch (vm.getStatus()) {
      case MigratingFrom:
        return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_MIGRATION_IN_PROGRESS);

      case NotResponding:
        return failCanDoAction(
            VdcBllMessages.ACTION_TYPE_FAILED_VM_STATUS_ILLEGAL,
            LocalizedVmStatus.from(VMStatus.NotResponding));

      case Paused:
        if (vm.getVmPauseStatus() == VmPauseStatus.EIO) {
          return failCanDoAction(VdcBllMessages.MIGRATE_PAUSED_EIO_VM_IS_NOT_SUPPORTED);
        }
        break;

      default:
    }

    if (!vm.isQualifyToMigrate()) {
      return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_NOT_RUNNING);
    }

    VmValidator vmValidator = new VmValidator(vm);

    if (!validate(
        vmValidator.vmNotHavingPluggedDiskSnapshots(
            VdcBllMessages.ACTION_TYPE_FAILED_VM_HAS_PLUGGED_DISK_SNAPSHOT))) {
      return false;
    }

    if (getDestinationVds() != null && getDestinationVds().getStatus() != VDSStatus.Up) {
      addCanDoActionMessage(VdcBllMessages.VAR__HOST_STATUS__UP);
      return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VDS_STATUS_ILLEGAL);
    }

    return validate(new SnapshotsValidator().vmNotDuringSnapshot(vm.getId()))
        // This check was added to prevent migration of VM while its disks are being migrated
        // TODO: replace it with a better solution
        && validate(
            new DiskImagesValidator(ImagesHandler.getPluggedActiveImagesForVm(vm.getId()))
                .diskImagesNotLocked())
        && SchedulingManager.getInstance()
            .canSchedule(
                getVdsGroup(),
                getVm(),
                getVdsBlackList(),
                getParameters().getInitialHosts(),
                getDestinationVdsId(),
                getReturnValue().getCanDoActionMessages());
  }