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);
  }
  @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();
    }
  }
  @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 DomainRouterVO deployRouter(
      final RouterDeploymentDefinition routerDeploymentDefinition, final boolean startRouter)
      throws InsufficientAddressCapacityException, InsufficientServerCapacityException,
          InsufficientCapacityException, StorageUnavailableException, ResourceUnavailableException {

    final ServiceOfferingVO routerOffering =
        _serviceOfferingDao.findById(routerDeploymentDefinition.getServiceOfferingId());
    final Account owner = routerDeploymentDefinition.getOwner();

    // Router is the network element, we don't know the hypervisor type yet.
    // Try to allocate the domR twice using diff hypervisors, and when
    // failed both times, throw the exception up
    final List<HypervisorType> hypervisors = getHypervisors(routerDeploymentDefinition);

    int allocateRetry = 0;
    int startRetry = 0;
    DomainRouterVO router = null;
    for (final Iterator<HypervisorType> iter = hypervisors.iterator(); iter.hasNext(); ) {
      final HypervisorType hType = iter.next();
      try {
        final long id = _routerDao.getNextInSequence(Long.class, "id");
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              String.format(
                  "Allocating the VR with id=%s in datacenter %s with the hypervisor type %s",
                  id, routerDeploymentDefinition.getDest().getDataCenter(), hType));
        }

        final String templateName =
            retrieveTemplateName(
                hType, routerDeploymentDefinition.getDest().getDataCenter().getId());
        final VMTemplateVO template = _templateDao.findRoutingTemplate(hType, templateName);

        if (template == null) {
          s_logger.debug(hType + " won't support system vm, skip it");
          continue;
        }

        final boolean offerHA = routerOffering.getOfferHA();

        // routerDeploymentDefinition.getVpc().getId() ==> do not use
        // VPC because it is not a VPC offering.
        final Long vpcId =
            routerDeploymentDefinition.getVpc() != null
                ? routerDeploymentDefinition.getVpc().getId()
                : null;

        long userId = CallContext.current().getCallingUserId();
        if (CallContext.current().getCallingAccount().getId() != owner.getId()) {
          final List<UserVO> userVOs = _userDao.listByAccount(owner.getAccountId());
          if (!userVOs.isEmpty()) {
            userId = userVOs.get(0).getId();
          }
        }

        router =
            new DomainRouterVO(
                id,
                routerOffering.getId(),
                routerDeploymentDefinition.getVirtualProvider().getId(),
                VirtualMachineName.getRouterName(id, s_vmInstanceName),
                template.getId(),
                template.getHypervisorType(),
                template.getGuestOSId(),
                owner.getDomainId(),
                owner.getId(),
                userId,
                routerDeploymentDefinition.isRedundant(),
                RedundantState.UNKNOWN,
                offerHA,
                false,
                vpcId);

        router.setDynamicallyScalable(template.isDynamicallyScalable());
        router.setRole(Role.VIRTUAL_ROUTER);
        router = _routerDao.persist(router);

        reallocateRouterNetworks(routerDeploymentDefinition, router, template, null);
        router = _routerDao.findById(router.getId());
      } catch (final InsufficientCapacityException ex) {
        if (allocateRetry < 2 && iter.hasNext()) {
          s_logger.debug(
              "Failed to allocate the VR with hypervisor type "
                  + hType
                  + ", retrying one more time");
          continue;
        } else {
          throw ex;
        }
      } finally {
        allocateRetry++;
      }

      if (startRouter) {
        try {
          router =
              startVirtualRouter(
                  router,
                  _accountMgr.getSystemUser(),
                  _accountMgr.getSystemAccount(),
                  routerDeploymentDefinition.getParams());
          break;
        } catch (final InsufficientCapacityException ex) {
          if (startRetry < 2 && iter.hasNext()) {
            s_logger.debug(
                "Failed to start the VR  "
                    + router
                    + " with hypervisor type "
                    + hType
                    + ", "
                    + "destroying it and recreating one more time");
            // destroy the router
            destroyRouter(
                router.getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), User.UID_SYSTEM);
            continue;
          } else {
            throw ex;
          }
        } finally {
          startRetry++;
        }
      } else {
        // return stopped router
        return router;
      }
    }

    return router;
  }
  public DomainRouterVO deployELBVm(
      Network guestNetwork, DeployDestination dest, Account owner, Map<Param, Object> params)
      throws ConcurrentOperationException, ResourceUnavailableException,
          InsufficientCapacityException {
    long dcId = dest.getDataCenter().getId();

    // lock guest network
    Long guestNetworkId = guestNetwork.getId();
    guestNetwork = _networkDao.acquireInLockTable(guestNetworkId);

    if (guestNetwork == null) {
      throw new ConcurrentOperationException("Unable to acquire network lock: " + guestNetworkId);
    }

    try {

      if (_networkModel.isNetworkSystem(guestNetwork)
          || guestNetwork.getGuestType() == Network.GuestType.Shared) {
        owner = _accountService.getSystemAccount();
      }

      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Starting a ELB vm for network configurations: " + guestNetwork + " in " + dest);
      }
      assert guestNetwork.getState() == Network.State.Implemented
              || guestNetwork.getState() == Network.State.Setup
              || guestNetwork.getState() == Network.State.Implementing
          : "Network is not yet fully implemented: " + guestNetwork;

      DataCenterDeployment plan = null;
      DomainRouterVO elbVm = null;

      plan = new DataCenterDeployment(dcId, dest.getPod().getId(), null, null, null, null);

      if (elbVm == null) {
        long id = _routerDao.getNextInSequence(Long.class, "id");
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("Creating the ELB vm " + id);
        }

        List<? extends NetworkOffering> offerings =
            _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork);
        NetworkOffering controlOffering = offerings.get(0);
        NetworkVO controlConfig =
            _networkMgr.setupNetwork(_systemAcct, controlOffering, plan, null, null, false).get(0);

        List<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(2);
        NicProfile guestNic = new NicProfile();
        guestNic.setDefaultNic(true);
        networks.add(new Pair<NetworkVO, NicProfile>(controlConfig, null));
        networks.add(new Pair<NetworkVO, NicProfile>((NetworkVO) guestNetwork, guestNic));

        VMTemplateVO template = _templateDao.findSystemVMTemplate(dcId);

        String typeString = "ElasticLoadBalancerVm";
        Long physicalNetworkId = _networkModel.getPhysicalNetworkId(guestNetwork);
        PhysicalNetworkServiceProvider provider =
            _physicalProviderDao.findByServiceProvider(physicalNetworkId, typeString);
        if (provider == null) {
          throw new CloudRuntimeException(
              "Cannot find service provider "
                  + typeString
                  + " in physical network "
                  + physicalNetworkId);
        }
        VirtualRouterProvider vrProvider =
            _vrProviderDao.findByNspIdAndType(
                provider.getId(), VirtualRouterProviderType.ElasticLoadBalancerVm);
        if (vrProvider == null) {
          throw new CloudRuntimeException(
              "Cannot find virtual router provider "
                  + typeString
                  + " as service provider "
                  + provider.getId());
        }

        elbVm =
            new DomainRouterVO(
                id,
                _elasticLbVmOffering.getId(),
                vrProvider.getId(),
                VirtualMachineName.getSystemVmName(id, _instance, _elbVmNamePrefix),
                template.getId(),
                template.getHypervisorType(),
                template.getGuestOSId(),
                owner.getDomainId(),
                owner.getId(),
                false,
                0,
                false,
                RedundantState.UNKNOWN,
                _elasticLbVmOffering.getOfferHA(),
                false,
                VirtualMachine.Type.ElasticLoadBalancerVm,
                null);
        elbVm.setRole(Role.LB);
        elbVm = _itMgr.allocate(elbVm, template, _elasticLbVmOffering, networks, plan, null, owner);
        // TODO: create usage stats
      }

      State state = elbVm.getState();
      if (state != State.Running) {
        elbVm =
            this.start(
                elbVm, _accountService.getSystemUser(), _accountService.getSystemAccount(), params);
      }

      return elbVm;
    } finally {
      _networkDao.releaseFromLockTable(guestNetworkId);
    }
  }
  @Override
  public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
    final Map<String, String> configs = _configDao.getConfiguration("AgentManager", params);
    _systemAcct = _accountService.getSystemAccount();
    _instance = configs.get("instance.name");
    if (_instance == null) {
      _instance = "VM";
    }
    _mgmtCidr = _configDao.getValue(Config.ManagementNetwork.key());
    _mgmtHost = _configDao.getValue(Config.ManagementHostIPAdr.key());

    boolean useLocalStorage =
        Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));

    _elasticLbVmRamSize =
        NumbersUtil.parseInt(
            configs.get(Config.ElasticLoadBalancerVmMemory.key()), DEFAULT_ELB_VM_RAMSIZE);
    _elasticLbvmCpuMHz =
        NumbersUtil.parseInt(
            configs.get(Config.ElasticLoadBalancerVmCpuMhz.key()), DEFAULT_ELB_VM_CPU_MHZ);
    _elasticLbvmNumCpu =
        NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmNumVcpu.key()), 1);
    _elasticLbVmOffering =
        new ServiceOfferingVO(
            "System Offering For Elastic LB VM",
            _elasticLbvmNumCpu,
            _elasticLbVmRamSize,
            _elasticLbvmCpuMHz,
            0,
            0,
            true,
            null,
            useLocalStorage,
            true,
            null,
            true,
            VirtualMachine.Type.ElasticLoadBalancerVm,
            true);
    _elasticLbVmOffering.setUniqueName(ServiceOffering.elbVmDefaultOffUniqueName);
    _elasticLbVmOffering = _serviceOfferingDao.persistSystemServiceOffering(_elasticLbVmOffering);

    String enabled = _configDao.getValue(Config.ElasticLoadBalancerEnabled.key());
    _enabled = (enabled == null) ? false : Boolean.parseBoolean(enabled);
    s_logger.info("Elastic Load balancer enabled: " + _enabled);
    if (_enabled) {
      String traffType = _configDao.getValue(Config.ElasticLoadBalancerNetwork.key());
      if ("guest".equalsIgnoreCase(traffType)) {
        _frontendTrafficType = TrafficType.Guest;
      } else if ("public".equalsIgnoreCase(traffType)) {
        _frontendTrafficType = TrafficType.Public;
      } else
        throw new ConfigurationException(
            "ELB: Traffic type for front end of load balancer has to be guest or public; found : "
                + traffType);
      s_logger.info("ELB: Elastic Load Balancer: will balance on " + traffType);
      int gcIntervalMinutes =
          NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmGcInterval.key()), 5);
      if (gcIntervalMinutes < 5) gcIntervalMinutes = 5;
      s_logger.info(
          "ELB: Elastic Load Balancer: scheduling GC to run every "
              + gcIntervalMinutes
              + " minutes");
      _gcThreadPool = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ELBVM-GC"));
      _gcThreadPool.scheduleAtFixedRate(
          new CleanupThread(), gcIntervalMinutes, gcIntervalMinutes, TimeUnit.MINUTES);
      _itMgr.registerGuru(VirtualMachine.Type.ElasticLoadBalancerVm, this);
    }

    return true;
  }
  private void initializeForImplicitPlannerTest(boolean preferred) {
    String plannerMode = new String("Strict");
    if (preferred) {
      plannerMode = new String("Preferred");
    }

    Map<String, String> details = new HashMap<String, String>();
    details.put("ImplicitDedicationMode", plannerMode);
    when(serviceOfferingDetailsDao.findDetails(offeringId)).thenReturn(details);

    // Initialize hosts in clusters
    HostVO host1 = mock(HostVO.class);
    when(host1.getId()).thenReturn(5L);
    HostVO host2 = mock(HostVO.class);
    when(host2.getId()).thenReturn(6L);
    HostVO host3 = mock(HostVO.class);
    when(host3.getId()).thenReturn(7L);
    List<HostVO> hostsInCluster1 = new ArrayList<HostVO>();
    List<HostVO> hostsInCluster2 = new ArrayList<HostVO>();
    List<HostVO> hostsInCluster3 = new ArrayList<HostVO>();
    hostsInCluster1.add(host1);
    hostsInCluster2.add(host2);
    hostsInCluster3.add(host3);
    when(resourceMgr.listAllHostsInCluster(1)).thenReturn(hostsInCluster1);
    when(resourceMgr.listAllHostsInCluster(2)).thenReturn(hostsInCluster2);
    when(resourceMgr.listAllHostsInCluster(3)).thenReturn(hostsInCluster3);

    // Mock vms on each host.
    long offeringIdForVmsOfThisAccount = 15L;
    long offeringIdForVmsOfOtherAccount = 16L;
    UserVmVO vm1 = mock(UserVmVO.class);
    when(vm1.getAccountId()).thenReturn(accountId);
    when(vm1.getServiceOfferingId()).thenReturn(offeringIdForVmsOfThisAccount);
    UserVmVO vm2 = mock(UserVmVO.class);
    when(vm2.getAccountId()).thenReturn(accountId);
    when(vm2.getServiceOfferingId()).thenReturn(offeringIdForVmsOfThisAccount);
    // Vm from different account
    UserVmVO vm3 = mock(UserVmVO.class);
    when(vm3.getAccountId()).thenReturn(201L);
    when(vm3.getServiceOfferingId()).thenReturn(offeringIdForVmsOfOtherAccount);
    List<VMInstanceVO> vmsForHost1 = new ArrayList<VMInstanceVO>();
    List<VMInstanceVO> vmsForHost2 = new ArrayList<VMInstanceVO>();
    List<VMInstanceVO> vmsForHost3 = new ArrayList<VMInstanceVO>();
    List<VMInstanceVO> stoppedVmsForHost = new ArrayList<VMInstanceVO>();
    // Host 2 is empty.
    vmsForHost1.add(vm1);
    vmsForHost1.add(vm2);
    vmsForHost3.add(vm3);
    when(vmInstanceDao.listUpByHostId(5L)).thenReturn(vmsForHost1);
    when(vmInstanceDao.listUpByHostId(6L)).thenReturn(vmsForHost2);
    when(vmInstanceDao.listUpByHostId(7L)).thenReturn(vmsForHost3);
    when(vmInstanceDao.listByLastHostId(5L)).thenReturn(stoppedVmsForHost);
    when(vmInstanceDao.listByLastHostId(6L)).thenReturn(stoppedVmsForHost);
    when(vmInstanceDao.listByLastHostId(7L)).thenReturn(stoppedVmsForHost);

    // Mock the offering with which the vm was created.
    ServiceOfferingVO offeringForVmOfThisAccount = mock(ServiceOfferingVO.class);
    when(serviceOfferingDao.findByIdIncludingRemoved(offeringIdForVmsOfThisAccount))
        .thenReturn(offeringForVmOfThisAccount);
    when(offeringForVmOfThisAccount.getDeploymentPlanner()).thenReturn(planner.getName());

    ServiceOfferingVO offeringForVMOfOtherAccount = mock(ServiceOfferingVO.class);
    when(serviceOfferingDao.findByIdIncludingRemoved(offeringIdForVmsOfOtherAccount))
        .thenReturn(offeringForVMOfOtherAccount);
    when(offeringForVMOfOtherAccount.getDeploymentPlanner()).thenReturn("FirstFitPlanner");
  }
  @Override
  public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
    if (s_logger.isInfoEnabled()) {
      s_logger.info("Start configuring secondary storage vm manager : " + name);
    }

    _name = name;

    ComponentLocator locator = ComponentLocator.getCurrentLocator();
    ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
    if (configDao == null) {
      throw new ConfigurationException("Unable to get the configuration dao.");
    }

    Map<String, String> configs = configDao.getConfiguration("management-server", params);

    _secStorageVmRamSize =
        NumbersUtil.parseInt(configs.get("secstorage.vm.ram.size"), DEFAULT_SS_VM_RAMSIZE);
    _secStorageVmCpuMHz =
        NumbersUtil.parseInt(configs.get("secstorage.vm.cpu.mhz"), DEFAULT_SS_VM_CPUMHZ);
    String useServiceVM = configDao.getValue("secondary.storage.vm");
    boolean _useServiceVM = false;
    if ("true".equalsIgnoreCase(useServiceVM)) {
      _useServiceVM = true;
    }

    String sslcopy = configDao.getValue("secstorage.encrypt.copy");
    if ("true".equalsIgnoreCase(sslcopy)) {
      _useSSlCopy = true;
    }

    _allowedInternalSites = configDao.getValue("secstorage.allowed.internal.sites");

    String value = configs.get("secstorage.capacityscan.interval");
    _capacityScanInterval = NumbersUtil.parseLong(value, DEFAULT_CAPACITY_SCAN_INTERVAL);

    _instance = configs.get("instance.name");
    if (_instance == null) {
      _instance = "DEFAULT";
    }

    Map<String, String> agentMgrConfigs = configDao.getConfiguration("AgentManager", params);
    _mgmt_host = agentMgrConfigs.get("host");
    if (_mgmt_host == null) {
      s_logger.warn(
          "Critical warning! Please configure your management server host address right after you have started your management server and then restart it, otherwise you won't have access to secondary storage");
    }

    value = agentMgrConfigs.get("port");
    _mgmt_port = NumbersUtil.parseInt(value, 8250);

    _listener = new SecondaryStorageListener(this, _agentMgr);
    _agentMgr.registerForHostEvents(_listener, true, false, true);

    _itMgr.registerGuru(VirtualMachine.Type.SecondaryStorageVm, this);

    _useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
    _serviceOffering =
        new ServiceOfferingVO(
            "System Offering For Secondary Storage VM",
            1,
            _secStorageVmRamSize,
            _secStorageVmCpuMHz,
            null,
            null,
            false,
            null,
            _useLocalStorage,
            true,
            null,
            true,
            VirtualMachine.Type.SecondaryStorageVm,
            true);
    _serviceOffering.setUniqueName("Cloud.com-SecondaryStorage");
    _serviceOffering = _offeringDao.persistSystemServiceOffering(_serviceOffering);

    // this can sometimes happen, if DB is manually or programmatically manipulated
    if (_serviceOffering == null) {
      String msg =
          "Data integrity problem : System Offering For Secondary Storage VM has been removed?";
      s_logger.error(msg);
      throw new ConfigurationException(msg);
    }

    if (_useServiceVM) {
      _loadScanner = new SystemVmLoadScanner<Long>(this);
      _loadScanner.initScan(STARTUP_DELAY, _capacityScanInterval);
    }
    if (s_logger.isInfoEnabled()) {
      s_logger.info("Secondary storage vm Manager is configured.");
    }
    return true;
  }
  protected Map<String, Object> createSecStorageVmInstance(
      long dataCenterId, SecondaryStorageVm.Role role) {
    HostVO secHost = _hostDao.findSecondaryStorageHost(dataCenterId);
    if (secHost == null) {
      String msg =
          "No secondary storage available in zone "
              + dataCenterId
              + ", cannot create secondary storage vm";
      s_logger.warn(msg);
      throw new CloudRuntimeException(msg);
    }

    long id = _secStorageVmDao.getNextInSequence(Long.class, "id");
    String name = VirtualMachineName.getSystemVmName(id, _instance, "s").intern();
    Account systemAcct = _accountMgr.getSystemAccount();

    DataCenterDeployment plan = new DataCenterDeployment(dataCenterId);
    DataCenter dc = _dcDao.findById(plan.getDataCenterId());

    List<NetworkOfferingVO> defaultOffering =
        _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemPublicNetwork);

    if (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()) {
      defaultOffering =
          _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemGuestNetwork);
    }

    List<NetworkOfferingVO> offerings =
        _networkMgr.getSystemAccountNetworkOfferings(
            NetworkOfferingVO.SystemControlNetwork, NetworkOfferingVO.SystemManagementNetwork);
    List<Pair<NetworkVO, NicProfile>> networks =
        new ArrayList<Pair<NetworkVO, NicProfile>>(offerings.size() + 1);
    NicProfile defaultNic = new NicProfile();
    defaultNic.setDefaultNic(true);
    defaultNic.setDeviceId(2);
    try {
      networks.add(
          new Pair<NetworkVO, NicProfile>(
              _networkMgr
                  .setupNetwork(systemAcct, defaultOffering.get(0), plan, null, null, false, false)
                  .get(0),
              defaultNic));
      for (NetworkOfferingVO offering : offerings) {
        networks.add(
            new Pair<NetworkVO, NicProfile>(
                _networkMgr
                    .setupNetwork(systemAcct, offering, plan, null, null, false, false)
                    .get(0),
                null));
      }
    } catch (ConcurrentOperationException e) {
      s_logger.info("Unable to setup due to concurrent operation. " + e);
      return new HashMap<String, Object>();
    }

    VMTemplateVO template = _templateDao.findSystemVMTemplate(dataCenterId);
    if (template == null) {
      s_logger.debug("Can't find a template to start");
      throw new CloudRuntimeException("Insufficient capacity exception");
    }

    SecondaryStorageVmVO secStorageVm =
        new SecondaryStorageVmVO(
            id,
            _serviceOffering.getId(),
            name,
            template.getId(),
            template.getHypervisorType(),
            template.getGuestOSId(),
            dataCenterId,
            systemAcct.getDomainId(),
            systemAcct.getId(),
            role,
            _serviceOffering.getOfferHA());
    try {
      secStorageVm =
          _itMgr.allocate(
              secStorageVm, template, _serviceOffering, networks, plan, null, systemAcct);
    } catch (InsufficientCapacityException e) {
      s_logger.warn("InsufficientCapacity", e);
      throw new CloudRuntimeException("Insufficient capacity exception", e);
    }

    Map<String, Object> context = new HashMap<String, Object>();
    context.put("secStorageVmId", secStorageVm.getId());
    return context;
  }