private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDeployment plan) {
    DataCenterVO mockDc = mock(DataCenterVO.class);
    VMInstanceVO vm = mock(VMInstanceVO.class);
    UserVmVO userVm = mock(UserVmVO.class);
    ServiceOfferingVO offering = mock(ServiceOfferingVO.class);

    AccountVO account = mock(AccountVO.class);
    when(account.getId()).thenReturn(accountId);
    when(account.getAccountId()).thenReturn(accountId);
    when(vmProfile.getOwner()).thenReturn(account);
    when(vmProfile.getVirtualMachine()).thenReturn(vm);
    when(vmProfile.getId()).thenReturn(12L);
    when(vmDao.findById(12L)).thenReturn(userVm);
    when(userVm.getAccountId()).thenReturn(accountId);

    when(vm.getDataCenterId()).thenReturn(dataCenterId);
    when(dcDao.findById(1L)).thenReturn(mockDc);
    when(plan.getDataCenterId()).thenReturn(dataCenterId);
    when(plan.getClusterId()).thenReturn(null);
    when(plan.getPodId()).thenReturn(null);
    when(configDao.getValue(anyString())).thenReturn("false").thenReturn("CPU");

    // Mock offering details.
    when(vmProfile.getServiceOffering()).thenReturn(offering);
    when(offering.getId()).thenReturn(offeringId);
    when(vmProfile.getServiceOfferingId()).thenReturn(offeringId);
    when(offering.getCpu()).thenReturn(noOfCpusInOffering);
    when(offering.getSpeed()).thenReturn(cpuSpeedInOffering);
    when(offering.getRamSize()).thenReturn(ramInOffering);

    List<Long> clustersWithEnoughCapacity = new ArrayList<Long>();
    clustersWithEnoughCapacity.add(1L);
    clustersWithEnoughCapacity.add(2L);
    clustersWithEnoughCapacity.add(3L);
    when(capacityDao.listClustersInZoneOrPodByHostCapacities(
            dataCenterId,
            noOfCpusInOffering * cpuSpeedInOffering,
            ramInOffering * 1024L * 1024L,
            CapacityVO.CAPACITY_TYPE_CPU,
            true))
        .thenReturn(clustersWithEnoughCapacity);

    Map<Long, Double> clusterCapacityMap = new HashMap<Long, Double>();
    clusterCapacityMap.put(1L, 2048D);
    clusterCapacityMap.put(2L, 2048D);
    clusterCapacityMap.put(3L, 2048D);
    Pair<List<Long>, Map<Long, Double>> clustersOrderedByCapacity =
        new Pair<List<Long>, Map<Long, Double>>(clustersWithEnoughCapacity, clusterCapacityMap);
    when(capacityDao.orderClustersByAggregateCapacity(
            dataCenterId, CapacityVO.CAPACITY_TYPE_CPU, true))
        .thenReturn(clustersOrderedByCapacity);

    List<Long> disabledClusters = new ArrayList<Long>();
    List<Long> clustersWithDisabledPods = new ArrayList<Long>();
    when(clusterDao.listDisabledClusters(dataCenterId, null)).thenReturn(disabledClusters);
    when(clusterDao.listClustersWithDisabledPods(dataCenterId))
        .thenReturn(clustersWithDisabledPods);
  }
  public void createOrUpdateIpCapacity(Long dcId, Long podId, short capacityType) {
    SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();

    List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
    capacitySC = _capacityDao.createSearchCriteria();
    capacitySC.addAnd("podId", SearchCriteria.Op.EQ, podId);
    capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId);
    capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType);

    int totalIPs;
    int allocatedIPs;
    capacities = _capacityDao.search(capacitySC, null);
    if (capacityType == CapacityVO.CAPACITY_TYPE_PRIVATE_IP) {
      totalIPs = _privateIPAddressDao.countIPs(podId, dcId, false);
      allocatedIPs = _privateIPAddressDao.countIPs(podId, dcId, true);
    } else if (capacityType == CapacityVO.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP) {
      totalIPs = _publicIPAddressDao.countIPsForNetwork(dcId, false, VlanType.VirtualNetwork);
      allocatedIPs = _publicIPAddressDao.countIPsForNetwork(dcId, true, VlanType.VirtualNetwork);
    } else {
      totalIPs = _publicIPAddressDao.countIPsForNetwork(dcId, false, VlanType.DirectAttached);
      allocatedIPs = _publicIPAddressDao.countIPsForNetwork(dcId, true, VlanType.DirectAttached);
    }

    if (capacities.size() == 0) {
      CapacityVO newPublicIPCapacity =
          new CapacityVO(null, dcId, podId, null, allocatedIPs, totalIPs, capacityType);
      _capacityDao.persist(newPublicIPCapacity);
    } else if (!(capacities.get(0).getUsedCapacity() == allocatedIPs
        && capacities.get(0).getTotalCapacity() == totalIPs)) {
      CapacityVO capacity = capacities.get(0);
      capacity.setUsedCapacity(allocatedIPs);
      capacity.setTotalCapacity(totalIPs);
      _capacityDao.update(capacity.getId(), capacity);
    }
  }
  private void createOrUpdateVlanCapacity(long dcId) {

    SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();

    List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
    capacitySC = _capacityDao.createSearchCriteria();
    capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId);
    capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, Capacity.CAPACITY_TYPE_VLAN);
    capacities = _capacityDao.search(capacitySC, null);

    int totalVlans = _dcDao.countZoneVlans(dcId, false);
    int allocatedVlans = _dcDao.countZoneVlans(dcId, true);

    if (capacities.size() == 0) {
      CapacityVO newPublicIPCapacity =
          new CapacityVO(
              null, dcId, null, null, allocatedVlans, totalVlans, Capacity.CAPACITY_TYPE_VLAN);
      _capacityDao.persist(newPublicIPCapacity);
    } else if (!(capacities.get(0).getUsedCapacity() == allocatedVlans
        && capacities.get(0).getTotalCapacity() == totalVlans)) {
      CapacityVO capacity = capacities.get(0);
      capacity.setUsedCapacity(allocatedVlans);
      capacity.setTotalCapacity(totalVlans);
      _capacityDao.update(capacity.getId(), capacity);
    }
  }
  // TODO: Get rid of this case once we've determined that the capacity listeners above have all the
  // changes
  // create capacity entries if none exist for this server
  private void createCapacityEntry(StartupCommand startup, HostVO server) {
    SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();
    capacitySC.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, server.getId());
    capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId());
    capacitySC.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId());

    if (startup instanceof StartupRoutingCommand) {
      SearchCriteria<CapacityVO> capacityCPU = _capacityDao.createSearchCriteria();
      capacityCPU.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, server.getId());
      capacityCPU.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId());
      capacityCPU.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId());
      capacityCPU.addAnd("capacityType", SearchCriteria.Op.EQ, CapacityVO.CAPACITY_TYPE_CPU);
      List<CapacityVO> capacityVOCpus = _capacityDao.search(capacitySC, null);
      Float cpuovercommitratio =
          Float.parseFloat(
              _clusterDetailsDao
                  .findDetail(server.getClusterId(), "cpuOvercommitRatio")
                  .getValue());
      Float memoryOvercommitRatio =
          Float.parseFloat(
              _clusterDetailsDao
                  .findDetail(server.getClusterId(), "memoryOvercommitRatio")
                  .getValue());

      if (capacityVOCpus != null && !capacityVOCpus.isEmpty()) {
        CapacityVO CapacityVOCpu = capacityVOCpus.get(0);
        long newTotalCpu =
            (long)
                (server.getCpus().longValue() * server.getSpeed().longValue() * cpuovercommitratio);
        if ((CapacityVOCpu.getTotalCapacity() <= newTotalCpu)
            || ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity())
                <= newTotalCpu)) {
          CapacityVOCpu.setTotalCapacity(newTotalCpu);
        } else if ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity()
                > newTotalCpu)
            && (CapacityVOCpu.getUsedCapacity() < newTotalCpu)) {
          CapacityVOCpu.setReservedCapacity(0);
          CapacityVOCpu.setTotalCapacity(newTotalCpu);
        } else {
          s_logger.debug(
              "What? new cpu is :"
                  + newTotalCpu
                  + ", old one is "
                  + CapacityVOCpu.getUsedCapacity()
                  + ","
                  + CapacityVOCpu.getReservedCapacity()
                  + ","
                  + CapacityVOCpu.getTotalCapacity());
        }
        _capacityDao.update(CapacityVOCpu.getId(), CapacityVOCpu);
      } else {
        CapacityVO capacity =
            new CapacityVO(
                server.getId(),
                server.getDataCenterId(),
                server.getPodId(),
                server.getClusterId(),
                0L,
                (long) (server.getCpus().longValue() * server.getSpeed().longValue()),
                CapacityVO.CAPACITY_TYPE_CPU);
        _capacityDao.persist(capacity);
      }

      SearchCriteria<CapacityVO> capacityMem = _capacityDao.createSearchCriteria();
      capacityMem.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, server.getId());
      capacityMem.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId());
      capacityMem.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId());
      capacityMem.addAnd("capacityType", SearchCriteria.Op.EQ, CapacityVO.CAPACITY_TYPE_MEMORY);
      List<CapacityVO> capacityVOMems = _capacityDao.search(capacityMem, null);

      if (capacityVOMems != null && !capacityVOMems.isEmpty()) {
        CapacityVO CapacityVOMem = capacityVOMems.get(0);
        long newTotalMem = (long) ((server.getTotalMemory()) * memoryOvercommitRatio);
        if (CapacityVOMem.getTotalCapacity() <= newTotalMem
            || (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity()
                <= newTotalMem)) {
          CapacityVOMem.setTotalCapacity(newTotalMem);
        } else if (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity()
                > newTotalMem
            && CapacityVOMem.getUsedCapacity() < newTotalMem) {
          CapacityVOMem.setReservedCapacity(0);
          CapacityVOMem.setTotalCapacity(newTotalMem);
        } else {
          s_logger.debug(
              "What? new cpu is :"
                  + newTotalMem
                  + ", old one is "
                  + CapacityVOMem.getUsedCapacity()
                  + ","
                  + CapacityVOMem.getReservedCapacity()
                  + ","
                  + CapacityVOMem.getTotalCapacity());
        }
        _capacityDao.update(CapacityVOMem.getId(), CapacityVOMem);
      } else {
        CapacityVO capacity =
            new CapacityVO(
                server.getId(),
                server.getDataCenterId(),
                server.getPodId(),
                server.getClusterId(),
                0L,
                server.getTotalMemory(),
                CapacityVO.CAPACITY_TYPE_MEMORY);
        _capacityDao.persist(capacity);
      }
    }
  }
  @DB
  @Override
  public void updateCapacityForHost(HostVO host) {
    // prepare the service offerings
    List<ServiceOfferingVO> offerings = _offeringsDao.listAllIncludingRemoved();
    Map<Long, ServiceOfferingVO> offeringsMap = new HashMap<Long, ServiceOfferingVO>();
    for (ServiceOfferingVO offering : offerings) {
      offeringsMap.put(offering.getId(), offering);
    }

    long usedCpu = 0;
    long usedMemory = 0;
    long reservedMemory = 0;
    long reservedCpu = 0;

    List<VMInstanceVO> vms = _vmDao.listUpByHostId(host.getId());
    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Found " + vms.size() + " VMs on host " + host.getId());
    }

    for (VMInstanceVO vm : vms) {
      ServiceOffering so = offeringsMap.get(vm.getServiceOfferingId());
      usedMemory += so.getRamSize() * 1024L * 1024L;
      usedCpu += so.getCpu() * so.getSpeed();
    }

    List<VMInstanceVO> vmsByLastHostId = _vmDao.listByLastHostId(host.getId());
    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Found " + vmsByLastHostId.size() + " VM, not running on host " + host.getId());
    }
    for (VMInstanceVO vm : vmsByLastHostId) {
      long secondsSinceLastUpdate =
          (DateUtil.currentGMTTime().getTime() - vm.getUpdateTime().getTime()) / 1000;
      if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) {
        ServiceOffering so = offeringsMap.get(vm.getServiceOfferingId());
        reservedMemory += so.getRamSize() * 1024L * 1024L;
        reservedCpu += so.getCpu() * so.getSpeed();
      }
    }

    CapacityVO cpuCap = _capacityDao.findByHostIdType(host.getId(), CapacityVO.CAPACITY_TYPE_CPU);
    CapacityVO memCap =
        _capacityDao.findByHostIdType(host.getId(), CapacityVO.CAPACITY_TYPE_MEMORY);

    if (cpuCap != null && memCap != null) {
      if (cpuCap.getUsedCapacity() == usedCpu && cpuCap.getReservedCapacity() == reservedCpu) {
        s_logger.debug(
            "No need to calibrate cpu capacity, host:"
                + host.getId()
                + " usedCpu: "
                + cpuCap.getUsedCapacity()
                + " reservedCpu: "
                + cpuCap.getReservedCapacity());
      } else if (cpuCap.getReservedCapacity() != reservedCpu) {
        s_logger.debug(
            "Calibrate reserved cpu for host: "
                + host.getId()
                + " old reservedCpu:"
                + cpuCap.getReservedCapacity()
                + " new reservedCpu:"
                + reservedCpu);
        cpuCap.setReservedCapacity(reservedCpu);
      } else if (cpuCap.getUsedCapacity() != usedCpu) {
        s_logger.debug(
            "Calibrate used cpu for host: "
                + host.getId()
                + " old usedCpu:"
                + cpuCap.getUsedCapacity()
                + " new usedCpu:"
                + usedCpu);
        cpuCap.setUsedCapacity(usedCpu);
      }

      if (memCap.getUsedCapacity() == usedMemory
          && memCap.getReservedCapacity() == reservedMemory) {
        s_logger.debug(
            "No need to calibrate memory capacity, host:"
                + host.getId()
                + " usedMem: "
                + memCap.getUsedCapacity()
                + " reservedMem: "
                + memCap.getReservedCapacity());
      } else if (memCap.getReservedCapacity() != reservedMemory) {
        s_logger.debug(
            "Calibrate reserved memory for host: "
                + host.getId()
                + " old reservedMem:"
                + memCap.getReservedCapacity()
                + " new reservedMem:"
                + reservedMemory);
        memCap.setReservedCapacity(reservedMemory);
      } else if (memCap.getUsedCapacity() != usedMemory) {
        /*
         * Didn't calibrate for used memory, because VMs can be in state(starting/migrating) that I don't know on which host they are
         * allocated
         */
        s_logger.debug(
            "Calibrate used memory for host: "
                + host.getId()
                + " old usedMem: "
                + memCap.getUsedCapacity()
                + " new usedMem: "
                + usedMemory);
        memCap.setUsedCapacity(usedMemory);
      }

      try {
        _capacityDao.update(cpuCap.getId(), cpuCap);
        _capacityDao.update(memCap.getId(), memCap);
      } catch (Exception e) {
        s_logger.error(
            "Caught exception while updating cpu/memory capacity for the host " + host.getId(), e);
      }
    } else {
      Transaction txn = Transaction.currentTxn();
      CapacityState capacityState =
          _configMgr.findClusterAllocationState(ApiDBUtils.findClusterById(host.getClusterId()))
                  == AllocationState.Disabled
              ? CapacityState.Disabled
              : CapacityState.Enabled;
      txn.start();
      CapacityVO capacity =
          new CapacityVO(
              host.getId(),
              host.getDataCenterId(),
              host.getPodId(),
              host.getClusterId(),
              usedMemory,
              host.getTotalMemory(),
              CapacityVO.CAPACITY_TYPE_MEMORY);
      capacity.setReservedCapacity(reservedMemory);
      capacity.setCapacityState(capacityState);
      _capacityDao.persist(capacity);

      capacity =
          new CapacityVO(
              host.getId(),
              host.getDataCenterId(),
              host.getPodId(),
              host.getClusterId(),
              usedCpu,
              (long) (host.getCpus().longValue() * host.getSpeed().longValue()),
              CapacityVO.CAPACITY_TYPE_CPU);
      capacity.setReservedCapacity(reservedCpu);
      capacity.setCapacityState(capacityState);
      _capacityDao.persist(capacity);
      txn.commit();
    }
  }
  @Override
  public boolean checkIfHostHasCapacity(
      long hostId,
      Integer cpu,
      long ram,
      boolean checkFromReservedCapacity,
      float cpuOvercommitRatio,
      float memoryOvercommitRatio,
      boolean considerReservedCapacity) {
    boolean hasCapacity = false;

    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Checking if host: "
              + hostId
              + " has enough capacity for requested CPU: "
              + cpu
              + " and requested RAM: "
              + ram
              + " , cpuOverprovisioningFactor: "
              + cpuOvercommitRatio);
    }

    CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU);
    CapacityVO capacityMem = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_MEMORY);

    if (capacityCpu == null || capacityMem == null) {
      if (capacityCpu == null) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "Cannot checkIfHostHasCapacity, Capacity entry for CPU not found in Db, for hostId: "
                  + hostId);
        }
      }
      if (capacityMem == null) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "Cannot checkIfHostHasCapacity, Capacity entry for RAM not found in Db, for hostId: "
                  + hostId);
        }
      }

      return false;
    }

    long usedCpu = capacityCpu.getUsedCapacity();
    long usedMem = capacityMem.getUsedCapacity();
    long reservedCpu = capacityCpu.getReservedCapacity();
    long reservedMem = capacityMem.getReservedCapacity();
    long actualTotalCpu = capacityCpu.getTotalCapacity();
    long actualTotalMem = capacityMem.getTotalCapacity();
    long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio);
    long totalMem = (long) (actualTotalMem * memoryOvercommitRatio);
    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Hosts's actual total CPU: "
              + actualTotalCpu
              + " and CPU after applying overprovisioning: "
              + totalCpu);
    }

    String failureReason = "";
    if (checkFromReservedCapacity) {
      long freeCpu = reservedCpu;
      long freeMem = reservedMem;

      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "We need to allocate to the last host again, so checking if there is enough reserved capacity");
        s_logger.debug("Reserved CPU: " + freeCpu + " , Requested CPU: " + cpu);
        s_logger.debug("Reserved RAM: " + freeMem + " , Requested RAM: " + ram);
      }
      /* alloc from reserved */
      if (reservedCpu >= cpu) {
        if (reservedMem >= ram) {
          hasCapacity = true;
        } else {
          failureReason = "Host does not have enough reserved RAM available";
        }
      } else {
        failureReason = "Host does not have enough reserved CPU available";
      }
    } else {

      long reservedCpuValueToUse = reservedCpu;
      long reservedMemValueToUse = reservedMem;

      if (!considerReservedCapacity) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "considerReservedCapacity is"
                  + considerReservedCapacity
                  + " , not considering reserved capacity for calculating free capacity");
        }
        reservedCpuValueToUse = 0;
        reservedMemValueToUse = 0;
      }
      long freeCpu = totalCpu - (reservedCpuValueToUse + usedCpu);
      long freeMem = totalMem - (reservedMemValueToUse + usedMem);

      if (s_logger.isDebugEnabled()) {
        s_logger.debug("Free CPU: " + freeCpu + " , Requested CPU: " + cpu);
        s_logger.debug("Free RAM: " + freeMem + " , Requested RAM: " + ram);
      }
      /* alloc from free resource */
      if ((reservedCpuValueToUse + usedCpu + cpu <= totalCpu)) {
        if ((reservedMemValueToUse + usedMem + ram <= totalMem)) {
          hasCapacity = true;
        } else {
          failureReason = "Host does not have enough RAM available";
        }
      } else {
        failureReason = "Host does not have enough CPU available";
      }
    }

    if (hasCapacity) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug("Host has enough CPU and RAM available");
      }

      s_logger.debug(
          "STATS: Can alloc CPU from host: "
              + hostId
              + ", used: "
              + usedCpu
              + ", reserved: "
              + reservedCpu
              + ", actual total: "
              + actualTotalCpu
              + ", total with overprovisioning: "
              + totalCpu
              + "; requested cpu:"
              + cpu
              + ",alloc_from_last_host?:"
              + checkFromReservedCapacity
              + " ,considerReservedCapacity?: "
              + considerReservedCapacity);

      s_logger.debug(
          "STATS: Can alloc MEM from host: "
              + hostId
              + ", used: "
              + usedMem
              + ", reserved: "
              + reservedMem
              + ", total: "
              + totalMem
              + "; requested mem: "
              + ram
              + ",alloc_from_last_host?:"
              + checkFromReservedCapacity
              + " ,considerReservedCapacity?: "
              + considerReservedCapacity);
    } else {

      if (checkFromReservedCapacity) {
        s_logger.debug(
            "STATS: Failed to alloc resource from host: "
                + hostId
                + " reservedCpu: "
                + reservedCpu
                + ", requested cpu: "
                + cpu
                + ", reservedMem: "
                + reservedMem
                + ", requested mem: "
                + ram);
      } else {
        s_logger.debug(
            "STATS: Failed to alloc resource from host: "
                + hostId
                + " reservedCpu: "
                + reservedCpu
                + ", used cpu: "
                + usedCpu
                + ", requested cpu: "
                + cpu
                + ", actual total cpu: "
                + actualTotalCpu
                + ", total cpu with overprovisioning: "
                + totalCpu
                + ", reservedMem: "
                + reservedMem
                + ", used Mem: "
                + usedMem
                + ", requested mem: "
                + ram
                + ", total Mem:"
                + totalMem
                + " ,considerReservedCapacity?: "
                + considerReservedCapacity);
      }

      if (s_logger.isDebugEnabled()) {
        s_logger.debug(failureReason + ", cannot allocate to this host.");
      }
    }

    return hasCapacity;
  }
  @DB
  @Override
  public void allocateVmCapacity(VirtualMachine vm, boolean fromLastHost) {

    long hostId = vm.getHostId();
    HostVO host = _hostDao.findById(hostId);
    long clusterId = host.getClusterId();
    float cpuOvercommitRatio =
        Float.parseFloat(_clusterDetailsDao.findDetail(clusterId, "cpuOvercommitRatio").getValue());
    float memoryOvercommitRatio =
        Float.parseFloat(
            _clusterDetailsDao.findDetail(clusterId, "memoryOvercommitRatio").getValue());

    ServiceOfferingVO svo = _offeringsDao.findById(vm.getServiceOfferingId());

    CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU);
    CapacityVO capacityMem = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_MEMORY);

    if (capacityCpu == null || capacityMem == null || svo == null) {
      return;
    }

    int cpu = (int) (svo.getCpu() * svo.getSpeed());
    long ram = (long) (svo.getRamSize() * 1024L * 1024L);

    Transaction txn = Transaction.currentTxn();

    try {
      txn.start();
      capacityCpu = _capacityDao.lockRow(capacityCpu.getId(), true);
      capacityMem = _capacityDao.lockRow(capacityMem.getId(), true);

      long usedCpu = capacityCpu.getUsedCapacity();
      long usedMem = capacityMem.getUsedCapacity();
      long reservedCpu = capacityCpu.getReservedCapacity();
      long reservedMem = capacityMem.getReservedCapacity();
      long actualTotalCpu = capacityCpu.getTotalCapacity();
      long actualTotalMem = capacityMem.getTotalCapacity();
      long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio);
      long totalMem = (long) (actualTotalMem * memoryOvercommitRatio);
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Hosts's actual total CPU: "
                + actualTotalCpu
                + " and CPU after applying overprovisioning: "
                + totalCpu);
      }

      long freeCpu = totalCpu - (reservedCpu + usedCpu);
      long freeMem = totalMem - (reservedMem + usedMem);

      if (s_logger.isDebugEnabled()) {
        s_logger.debug("We are allocating VM, increasing the used capacity of this host:" + hostId);
        s_logger.debug(
            "Current Used CPU: " + usedCpu + " , Free CPU:" + freeCpu + " ,Requested CPU: " + cpu);
        s_logger.debug(
            "Current Used RAM: " + usedMem + " , Free RAM:" + freeMem + " ,Requested RAM: " + ram);
      }
      capacityCpu.setUsedCapacity(usedCpu + cpu);
      capacityMem.setUsedCapacity(usedMem + ram);

      if (fromLastHost) {
        /* alloc from reserved */
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "We are allocating VM to the last host again, so adjusting the reserved capacity if it is not less than required");
          s_logger.debug("Reserved CPU: " + reservedCpu + " , Requested CPU: " + cpu);
          s_logger.debug("Reserved RAM: " + reservedMem + " , Requested RAM: " + ram);
        }
        if (reservedCpu >= cpu && reservedMem >= ram) {
          capacityCpu.setReservedCapacity(reservedCpu - cpu);
          capacityMem.setReservedCapacity(reservedMem - ram);
        }
      } else {
        /* alloc from free resource */
        if (!((reservedCpu + usedCpu + cpu <= totalCpu)
            && (reservedMem + usedMem + ram <= totalMem))) {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                "Host doesnt seem to have enough free capacity, but increasing the used capacity anyways, since the VM is already starting on this host ");
          }
        }
      }

      s_logger.debug(
          "CPU STATS after allocation: for host: "
              + hostId
              + ", old used: "
              + usedCpu
              + ", old reserved: "
              + reservedCpu
              + ", actual total: "
              + actualTotalCpu
              + ", total with overprovisioning: "
              + totalCpu
              + "; new used:"
              + capacityCpu.getUsedCapacity()
              + ", reserved:"
              + capacityCpu.getReservedCapacity()
              + "; requested cpu:"
              + cpu
              + ",alloc_from_last:"
              + fromLastHost);

      s_logger.debug(
          "RAM STATS after allocation: for host: "
              + hostId
              + ", old used: "
              + usedMem
              + ", old reserved: "
              + reservedMem
              + ", total: "
              + totalMem
              + "; new used: "
              + capacityMem.getUsedCapacity()
              + ", reserved: "
              + capacityMem.getReservedCapacity()
              + "; requested mem: "
              + ram
              + ",alloc_from_last:"
              + fromLastHost);

      _capacityDao.update(capacityCpu.getId(), capacityCpu);
      _capacityDao.update(capacityMem.getId(), capacityMem);
      txn.commit();
    } catch (Exception e) {
      txn.rollback();
      return;
    }
  }
  @DB
  @Override
  public boolean releaseVmCapacity(
      VirtualMachine vm, boolean moveFromReserved, boolean moveToReservered, Long hostId) {
    ServiceOfferingVO svo = _offeringsDao.findById(vm.getServiceOfferingId());
    CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU);
    CapacityVO capacityMemory =
        _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_MEMORY);
    Long clusterId = null;
    if (hostId != null) {
      HostVO host = _hostDao.findById(hostId);
      clusterId = host.getClusterId();
    }
    if (capacityCpu == null || capacityMemory == null || svo == null) {
      return false;
    }

    Transaction txn = Transaction.currentTxn();
    try {
      txn.start();

      capacityCpu = _capacityDao.lockRow(capacityCpu.getId(), true);
      capacityMemory = _capacityDao.lockRow(capacityMemory.getId(), true);

      long usedCpu = capacityCpu.getUsedCapacity();
      long usedMem = capacityMemory.getUsedCapacity();
      long reservedCpu = capacityCpu.getReservedCapacity();
      long reservedMem = capacityMemory.getReservedCapacity();
      long actualTotalCpu = capacityCpu.getTotalCapacity();
      float cpuOvercommitRatio =
          Float.parseFloat(
              _clusterDetailsDao.findDetail(clusterId, "cpuOvercommitRatio").getValue());
      float memoryOvercommitRatio =
          Float.parseFloat(
              _clusterDetailsDao.findDetail(clusterId, "memoryOvercommitRatio").getValue());
      int vmCPU = (int) (svo.getCpu() * svo.getSpeed());
      long vmMem = (long) (svo.getRamSize() * 1024L * 1024L);
      long actualTotalMem = capacityMemory.getTotalCapacity();
      long totalMem = (long) (actualTotalMem * memoryOvercommitRatio);
      long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio);
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Hosts's actual total CPU: "
                + actualTotalCpu
                + " and CPU after applying overprovisioning: "
                + totalCpu);
        s_logger.debug(
            "Hosts's actual total RAM: "
                + actualTotalMem
                + " and RAM after applying overprovisioning: "
                + totalMem);
      }

      if (!moveFromReserved) {
        /* move resource from used */
        if (usedCpu >= vmCPU) {
          capacityCpu.setUsedCapacity(usedCpu - vmCPU);
        }
        if (usedMem >= vmMem) {
          capacityMemory.setUsedCapacity(usedMem - vmMem);
        }

        if (moveToReservered) {
          if (reservedCpu + vmCPU <= totalCpu) {
            capacityCpu.setReservedCapacity(reservedCpu + vmCPU);
          }
          if (reservedMem + vmMem <= totalMem) {
            capacityMemory.setReservedCapacity(reservedMem + vmMem);
          }
        }
      } else {
        if (reservedCpu >= vmCPU) {
          capacityCpu.setReservedCapacity(reservedCpu - vmCPU);
        }
        if (reservedMem >= vmMem) {
          capacityMemory.setReservedCapacity(reservedMem - vmMem);
        }
      }

      s_logger.debug(
          "release cpu from host: "
              + hostId
              + ", old used: "
              + usedCpu
              + ",reserved: "
              + reservedCpu
              + ", actual total: "
              + actualTotalCpu
              + ", total with overprovisioning: "
              + totalCpu
              + "; new used: "
              + capacityCpu.getUsedCapacity()
              + ",reserved:"
              + capacityCpu.getReservedCapacity()
              + "; movedfromreserved: "
              + moveFromReserved
              + ",moveToReservered"
              + moveToReservered);

      s_logger.debug(
          "release mem from host: "
              + hostId
              + ", old used: "
              + usedMem
              + ",reserved: "
              + reservedMem
              + ", total: "
              + totalMem
              + "; new used: "
              + capacityMemory.getUsedCapacity()
              + ",reserved:"
              + capacityMemory.getReservedCapacity()
              + "; movedfromreserved: "
              + moveFromReserved
              + ",moveToReservered"
              + moveToReservered);

      _capacityDao.update(capacityCpu.getId(), capacityCpu);
      _capacityDao.update(capacityMemory.getId(), capacityMemory);
      txn.commit();
      return true;
    } catch (Exception e) {
      s_logger.debug("Failed to transit vm's state, due to " + e.getMessage());
      txn.rollback();
      return false;
    }
  }
 @Override
 public void processPrepareMaintenaceEventAfter(Long hostId) {
   _capacityDao.removeBy(Capacity.CAPACITY_TYPE_MEMORY, null, null, null, hostId);
   _capacityDao.removeBy(Capacity.CAPACITY_TYPE_CPU, null, null, null, hostId);
 }
  public void checkForAlerts() {

    recalculateCapacity();

    // abort if we can't possibly send an alert...
    if (_emailAlert == null) {
      return;
    }

    // Get all datacenters, pods and clusters in the system.
    List<DataCenterVO> dataCenterList = _dcDao.listAll();
    List<ClusterVO> clusterList = _clusterDao.listAll();
    List<HostPodVO> podList = _podDao.listAll();
    // Get capacity types at different levels
    List<Short> dataCenterCapacityTypes = getCapacityTypesAtZoneLevel();
    List<Short> podCapacityTypes = getCapacityTypesAtPodLevel();
    List<Short> clusterCapacityTypes = getCapacityTypesAtClusterLevel();

    // Generate Alerts for Zone Level capacities
    for (DataCenterVO dc : dataCenterList) {
      for (Short capacityType : dataCenterCapacityTypes) {
        List<SummedCapacity> capacity = new ArrayList<SummedCapacity>();
        capacity = _capacityDao.findCapacityBy(capacityType.intValue(), dc.getId(), null, null);

        if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) {
          capacity.add(getUsedStats(capacityType, dc.getId(), null, null));
        }
        if (capacity == null || capacity.size() == 0) {
          continue;
        }
        double totalCapacity = capacity.get(0).getTotalCapacity();
        double usedCapacity = capacity.get(0).getUsedCapacity();
        if (totalCapacity != 0
            && usedCapacity / totalCapacity > _capacityTypeThresholdMap.get(capacityType)) {
          generateEmailAlert(dc, null, null, totalCapacity, usedCapacity, capacityType);
        }
      }
    }

    // Generate Alerts for Pod Level capacities
    for (HostPodVO pod : podList) {
      for (Short capacityType : podCapacityTypes) {
        List<SummedCapacity> capacity =
            _capacityDao.findCapacityBy(
                capacityType.intValue(), pod.getDataCenterId(), pod.getId(), null);
        if (capacity == null || capacity.size() == 0) {
          continue;
        }
        double totalCapacity = capacity.get(0).getTotalCapacity();
        double usedCapacity = capacity.get(0).getUsedCapacity();
        if (totalCapacity != 0
            && usedCapacity / totalCapacity > _capacityTypeThresholdMap.get(capacityType)) {
          generateEmailAlert(
              ApiDBUtils.findZoneById(pod.getDataCenterId()),
              pod,
              null,
              totalCapacity,
              usedCapacity,
              capacityType);
        }
      }
    }

    // Generate Alerts for Cluster Level capacities
    for (ClusterVO cluster : clusterList) {
      for (Short capacityType : clusterCapacityTypes) {
        List<SummedCapacity> capacity = new ArrayList<SummedCapacity>();
        float overProvFactor = 1f;
        capacity =
            _capacityDao.findCapacityBy(
                capacityType.intValue(), cluster.getDataCenterId(), null, cluster.getId());

        if (capacityType == Capacity.CAPACITY_TYPE_STORAGE) {
          capacity.add(
              getUsedStats(
                  capacityType, cluster.getDataCenterId(), cluster.getPodId(), cluster.getId()));
        }
        if (capacity == null || capacity.size() == 0) {
          continue;
        }
        if (capacityType == Capacity.CAPACITY_TYPE_CPU) {
          overProvFactor = ApiDBUtils.getCpuOverprovisioningFactor();
        }

        double totalCapacity = capacity.get(0).getTotalCapacity() * overProvFactor;
        double usedCapacity =
            capacity.get(0).getUsedCapacity() + capacity.get(0).getReservedCapacity();
        if (totalCapacity != 0
            && usedCapacity / totalCapacity > _capacityTypeThresholdMap.get(capacityType)) {
          generateEmailAlert(
              ApiDBUtils.findZoneById(cluster.getDataCenterId()),
              ApiDBUtils.findPodById(cluster.getPodId()),
              cluster,
              totalCapacity,
              usedCapacity,
              capacityType);
        }
      }
    }
  }