@Override
  public List<UserVmVO> listVirtualNetworkInstancesByAcctAndZone(long accountId, long dcId) {
    if (AccountDataCenterVirtualSearch == null) {
      ServiceOfferingDao offeringDao =
          ComponentLocator.getLocator("management-server").getDao(ServiceOfferingDao.class);
      SearchBuilder<ServiceOfferingVO> offeringSearch = offeringDao.createSearchBuilder();
      offeringSearch.and(
          "guestIpType", offeringSearch.entity().getGuestIpType(), SearchCriteria.Op.EQ);

      AccountDataCenterVirtualSearch = createSearchBuilder();
      AccountDataCenterVirtualSearch.and(
          "account", AccountDataCenterVirtualSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
      AccountDataCenterVirtualSearch.and(
          "dc", AccountDataCenterVirtualSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
      AccountDataCenterVirtualSearch.join(
          "offeringSearch",
          offeringSearch,
          AccountDataCenterVirtualSearch.entity().getServiceOfferingId(),
          offeringSearch.entity().getId());
      AccountDataCenterVirtualSearch.done();
    }

    SearchCriteria sc = AccountDataCenterVirtualSearch.create();
    sc.setParameters("account", accountId);
    sc.setParameters("dc", dcId);
    sc.setJoinParameters("offeringSearch", "guestIpType", ServiceOffering.GuestIpType.Virtualized);

    return listActiveBy(sc);
  }
  /** @param network */
  private void mockDAOs(final NetworkVO network, final NetworkOfferingVO offering) {
    when(_networkDao.acquireInLockTable(
            network.getId(), NetworkOrchestrationService.NetworkLockTimeout.value()))
        .thenReturn(network);
    when(_networksDao.acquireInLockTable(
            network.getId(), NetworkOrchestrationService.NetworkLockTimeout.value()))
        .thenReturn(network);
    when(_physicalProviderDao.findByServiceProvider(0L, "VirtualRouter"))
        .thenReturn(new PhysicalNetworkServiceProviderVO());
    when(_vrProviderDao.findByNspIdAndType(0L, Type.VirtualRouter))
        .thenReturn(new VirtualRouterProviderVO());
    when(_networkOfferingDao.findById(0L)).thenReturn(offering);
    // watchit: (in this test) there can be only one
    when(_routerDao.getNextInSequence(Long.class, "id")).thenReturn(0L);
    final ServiceOfferingVO svcoff =
        new ServiceOfferingVO(
            "name",
            /* cpu */ 1,
            /* ramsize */ 1024 * 1024,
            /* (clock?)speed */ 1024 * 1024 * 1024,
            /* rateMbps */ 1,
            /* multicastRateMbps */ 0,
            /* offerHA */ false,
            "displayText",
            ProvisioningType.THIN,
            /* useLocalStorage */ false,
            /* recreatable */ false,
            "tags",
            /* systemUse */ false,
            VirtualMachine.Type.DomainRouter,
            /* defaultUse */ false);
    when(_serviceOfferingDao.findById(0L)).thenReturn(svcoff);
    final DomainRouterVO router =
        new DomainRouterVO(
            /* id */ 1L,
            /* serviceOfferingId */ 1L,
            /* elementId */ 0L,
            "name",
            /* templateId */ 0L,
            HypervisorType.XenServer,
            /* guestOSId */ 0L,
            /* domainId */ 0L,
            /* accountId */ 1L,
            /* userId */ 1L,
            /* isRedundantRouter */ false,
            RedundantState.UNKNOWN,
            /* haEnabled */ false,
            /* stopPending */ false,
            /* vpcId */ null);

    when(_routerDao.getNextInSequence(Long.class, "id")).thenReturn(1L);
    when(_templateDao.findRoutingTemplate(
            HypervisorType.XenServer, "SystemVM Template (XenServer)"))
        .thenReturn(new VMTemplateVO());
    when(_routerDao.persist(any(DomainRouterVO.class))).thenReturn(router);
    when(_routerDao.findById(router.getId())).thenReturn(router);
  }
  @Override
  public void reallocateRouterNetworks(
      final RouterDeploymentDefinition routerDeploymentDefinition,
      final VirtualRouter router,
      final VMTemplateVO template,
      final HypervisorType hType)
      throws ConcurrentOperationException, InsufficientCapacityException {
    final ServiceOfferingVO routerOffering =
        _serviceOfferingDao.findById(routerDeploymentDefinition.getServiceOfferingId());

    final LinkedHashMap<Network, List<? extends NicProfile>> networks =
        configureDefaultNics(routerDeploymentDefinition);

    _itMgr.allocate(
        router.getInstanceName(),
        template,
        routerOffering,
        networks,
        routerDeploymentDefinition.getPlan(),
        hType);
  }
 private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool) {
   List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId());
   long totalSize = 0;
   for (VolumeVO volume : volumes) {
     if (volume.getInstanceId() == null) continue;
     Long vmId = volume.getInstanceId();
     UserVm vm = _userVMDao.findById(vmId);
     if (vm == null) continue;
     ServiceOffering offering = _offeringsDao.findById(vm.getServiceOfferingId());
     List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
     long pathCount = 0;
     long memorySnapshotSize = 0;
     for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
       if (_vmSnapshotDao.listByParent(vmSnapshotVO.getId()).size() == 0) pathCount++;
       if (vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory)
         memorySnapshotSize += (offering.getRamSize() * 1024 * 1024);
     }
     if (pathCount <= 1) totalSize = totalSize + memorySnapshotSize;
     else totalSize = totalSize + volume.getSize() * (pathCount - 1) + memorySnapshotSize;
   }
   return totalSize;
 }
  @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;
  }
  @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;
  }
  @Override
  public boolean addUserData(NicProfile nic, VirtualMachineProfile profile) {
    UserVmVO vm = _vmDao.findById(profile.getVirtualMachine().getId());
    _vmDao.loadDetails(vm);

    String serviceOffering =
        _serviceOfferingDao
            .findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId())
            .getDisplayText();
    String zoneName = _dcDao.findById(vm.getDataCenterId()).getName();
    NicVO nvo = _nicDao.findById(nic.getId());
    VmDataCommand cmd =
        new VmDataCommand(
            nvo.getIPv4Address(), vm.getInstanceName(), _ntwkModel.getExecuteInSeqNtwkElmtCmd());
    // if you add new metadata files, also edit
    // systemvm/patches/debian/config/var/www/html/latest/.htaccess
    cmd.addVmData("userdata", "user-data", vm.getUserData());
    cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering));
    cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName));
    cmd.addVmData("metadata", "local-ipv4", nic.getIPv4Address());
    cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vm.getInstanceName()));
    cmd.addVmData("metadata", "public-ipv4", nic.getIPv4Address());
    cmd.addVmData("metadata", "public-hostname", StringUtils.unicodeEscape(vm.getInstanceName()));
    cmd.addVmData("metadata", "instance-id", String.valueOf(vm.getId()));
    cmd.addVmData("metadata", "vm-id", String.valueOf(vm.getInstanceName()));
    cmd.addVmData("metadata", "public-keys", null);
    String cloudIdentifier = _configDao.getValue("cloud.identifier");
    if (cloudIdentifier == null) {
      cloudIdentifier = "";
    } else {
      cloudIdentifier = "CloudStack-{" + cloudIdentifier + "}";
    }
    cmd.addVmData("metadata", "cloud-identifier", cloudIdentifier);

    List<PhysicalNetworkVO> phys = _phynwDao.listByZone(vm.getDataCenterId());
    if (phys.isEmpty()) {
      throw new CloudRuntimeException(
          String.format("Cannot find physical network in zone %s", vm.getDataCenterId()));
    }
    if (phys.size() > 1) {
      throw new CloudRuntimeException(
          String.format(
              "Baremetal only supports one physical network in zone, but zone %s has %s physical networks",
              vm.getDataCenterId(), phys.size()));
    }
    PhysicalNetworkVO phy = phys.get(0);

    QueryBuilder<BaremetalPxeVO> sc = QueryBuilder.create(BaremetalPxeVO.class);
    // TODO: handle both kickstart and PING
    // sc.addAnd(sc.getEntity().getPodId(), Op.EQ, vm.getPodIdToDeployIn());
    sc.and(sc.entity().getPhysicalNetworkId(), Op.EQ, phy.getId());
    BaremetalPxeVO pxeVo = sc.find();
    if (pxeVo == null) {
      throw new CloudRuntimeException(
          "No PXE server found in pod: "
              + vm.getPodIdToDeployIn()
              + ", you need to add it before starting VM");
    }

    try {
      Answer ans = _agentMgr.send(pxeVo.getHostId(), cmd);
      if (!ans.getResult()) {
        s_logger.debug(
            String.format(
                "Add userdata to vm:%s failed because %s", vm.getInstanceName(), ans.getDetails()));
        return false;
      } else {
        return true;
      }
    } catch (Exception e) {
      s_logger.debug(String.format("Add userdata to vm:%s failed", vm.getInstanceName()), e);
      return false;
    }
  }
  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;
  }