@Override
  public String reserveVirtualMachine(
      VMEntityVO vmEntityVO, String plannerToUse, DeploymentPlan planToDeploy, ExcludeList exclude)
      throws InsufficientCapacityException, ResourceUnavailableException {

    // call planner and get the deployDestination.
    // load vm instance and offerings and call virtualMachineManagerImpl
    // FIXME: profile should work on VirtualMachineEntity
    VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid());
    VirtualMachineProfileImpl<VMInstanceVO> vmProfile =
        new VirtualMachineProfileImpl<VMInstanceVO>(vm);
    DataCenterDeployment plan =
        new DataCenterDeployment(
            vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null);
    if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
      plan =
          new DataCenterDeployment(
              planToDeploy.getDataCenterId(),
              planToDeploy.getPodId(),
              planToDeploy.getClusterId(),
              planToDeploy.getHostId(),
              planToDeploy.getPoolId(),
              planToDeploy.getPhysicalNetworkId());
    }

    List<VolumeVO> vols = _volsDao.findReadyRootVolumesByInstance(vm.getId());
    if (!vols.isEmpty()) {
      VolumeVO vol = vols.get(0);
      StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId());
      if (!pool.isInMaintenance()) {
        long rootVolDcId = pool.getDataCenterId();
        Long rootVolPodId = pool.getPodId();
        Long rootVolClusterId = pool.getClusterId();
        if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
          Long clusterIdSpecified = planToDeploy.getClusterId();
          if (clusterIdSpecified != null && rootVolClusterId != null) {
            if (rootVolClusterId.longValue() != clusterIdSpecified.longValue()) {
              // cannot satisfy the plan passed in to the
              // planner
              throw new ResourceUnavailableException(
                  "Root volume is ready in different cluster, Deployment plan provided cannot be satisfied, unable to create a deployment for "
                      + vm,
                  Cluster.class,
                  clusterIdSpecified);
            }
          }
          plan =
              new DataCenterDeployment(
                  planToDeploy.getDataCenterId(),
                  planToDeploy.getPodId(),
                  planToDeploy.getClusterId(),
                  planToDeploy.getHostId(),
                  vol.getPoolId(),
                  null,
                  null);
        } else {
          plan =
              new DataCenterDeployment(
                  rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId(), null, null);
        }
      }
    }

    DeploymentPlanner planner = ComponentContext.getComponent(plannerToUse);
    DeployDestination dest = null;

    if (planner.canHandle(vmProfile, plan, exclude)) {
      dest = planner.plan(vmProfile, plan, exclude);
    }

    if (dest != null) {
      // save destination with VMEntityVO
      VMReservationVO vmReservation =
          new VMReservationVO(
              vm.getId(),
              dest.getDataCenter().getId(),
              dest.getPod().getId(),
              dest.getCluster().getId(),
              dest.getHost().getId());
      Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
      for (Volume vo : dest.getStorageForDisks().keySet()) {
        volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId());
      }
      vmReservation.setVolumeReservation(volumeReservationMap);

      vmEntityVO.setVmReservation(vmReservation);
      _vmEntityDao.persist(vmEntityVO);

      return vmReservation.getUuid();
    } else {
      throw new InsufficientServerCapacityException(
          "Unable to create a deployment for " + vmProfile,
          DataCenter.class,
          plan.getDataCenterId());
    }
  }
  @Override
  protected List<StoragePool> select(
      DiskProfile dskCh,
      VirtualMachineProfile vmProfile,
      DeploymentPlan plan,
      ExcludeList avoid,
      int returnUpTo) {

    List<StoragePool> suitablePools = new ArrayList<StoragePool>();

    s_logger.debug("LocalStoragePoolAllocator trying to find storage pool to fit the vm");

    if (!dskCh.useLocalStorage()) {
      return suitablePools;
    }

    // data disk and host identified from deploying vm (attach volume case)
    if (dskCh.getType() == Volume.Type.DATADISK && plan.getHostId() != null) {
      List<StoragePoolHostVO> hostPools = _poolHostDao.listByHostId(plan.getHostId());
      for (StoragePoolHostVO hostPool : hostPools) {
        StoragePoolVO pool = _storagePoolDao.findById(hostPool.getPoolId());
        if (pool != null && pool.isLocal()) {
          StoragePool pol = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(pool.getId());
          if (filter(avoid, pol, dskCh, plan)) {
            s_logger.debug(
                "Found suitable local storage pool " + pool.getId() + ", adding to list");
            suitablePools.add(pol);
          } else {
            avoid.addPool(pool.getId());
          }
        }

        if (suitablePools.size() == returnUpTo) {
          break;
        }
      }
    } else {
      if (plan.getPodId() == null) {
        // zone wide primary storage deployment
        return null;
      }
      List<StoragePoolVO> availablePools =
          _storagePoolDao.findLocalStoragePoolsByTags(
              plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), dskCh.getTags());
      for (StoragePoolVO pool : availablePools) {
        if (suitablePools.size() == returnUpTo) {
          break;
        }
        StoragePool pol = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(pool.getId());
        if (filter(avoid, pol, dskCh, plan)) {
          suitablePools.add(pol);
        } else {
          avoid.addPool(pool.getId());
        }
      }

      // add remaining pools in cluster, that did not match tags, to avoid
      // set
      List<StoragePoolVO> allPools =
          _storagePoolDao.findLocalStoragePoolsByTags(
              plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), null);
      allPools.removeAll(availablePools);
      for (StoragePoolVO pool : allPools) {
        avoid.addPool(pool.getId());
      }
    }

    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "LocalStoragePoolAllocator returning "
              + suitablePools.size()
              + " suitable storage pools");
    }

    return suitablePools;
  }