@Override
  public Pair<AfterScanAction, Object> scanPool(Long pool) {
    long dataCenterId = pool.longValue();

    List<SecondaryStorageVmVO> ssVms =
        _secStorageVmDao.getSecStorageVmListInStates(
            SecondaryStorageVm.Role.templateProcessor,
            dataCenterId,
            State.Running,
            State.Migrating,
            State.Starting,
            State.Stopped,
            State.Stopping);
    int vmSize = (ssVms == null) ? 0 : ssVms.size();
    List<HostVO> ssHosts = _hostDao.listSecondaryStorageHosts(dataCenterId);
    int hostSize = (ssHosts == null) ? 0 : ssHosts.size();
    if (hostSize > vmSize) {
      s_logger.info(
          "No secondary storage vms found in datacenter id="
              + dataCenterId
              + ", starting a new one");
      return new Pair<AfterScanAction, Object>(
          AfterScanAction.expand, SecondaryStorageVm.Role.templateProcessor);
    }

    return new Pair<AfterScanAction, Object>(
        AfterScanAction.nop, SecondaryStorageVm.Role.templateProcessor);
  }
  @Override
  public boolean finalizeDeployment(
      Commands cmds,
      VirtualMachineProfile<SecondaryStorageVmVO> profile,
      DeployDestination dest,
      ReservationContext context) {

    finalizeCommandsOnStart(cmds, profile);

    SecondaryStorageVmVO secVm = profile.getVirtualMachine();
    DataCenter dc = dest.getDataCenter();
    List<NicProfile> nics = profile.getNics();
    for (NicProfile nic : nics) {
      if ((nic.getTrafficType() == TrafficType.Public
              && dc.getNetworkType() == NetworkType.Advanced)
          || (nic.getTrafficType() == TrafficType.Guest
              && (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()))) {
        secVm.setPublicIpAddress(nic.getIp4Address());
        secVm.setPublicNetmask(nic.getNetmask());
        secVm.setPublicMacAddress(nic.getMacAddress());
      } else if (nic.getTrafficType() == TrafficType.Management) {
        secVm.setPrivateIpAddress(nic.getIp4Address());
        secVm.setPrivateMacAddress(nic.getMacAddress());
      }
    }
    _secStorageVmDao.update(secVm.getId(), secVm);
    return true;
  }
 @Override
 public void finalizeExpunge(SecondaryStorageVmVO vm) {
   vm.setPublicIpAddress(null);
   vm.setPublicMacAddress(null);
   vm.setPublicNetmask(null);
   _secStorageVmDao.update(vm.getId(), vm);
 }
  public SecondaryStorageVmVO assignSecStorageVmFromRunningPool(
      long dataCenterId, SecondaryStorageVm.Role role) {

    if (s_logger.isTraceEnabled()) {
      s_logger.trace(
          "Assign  secondary storage vm from running pool for request from data center : "
              + dataCenterId);
    }

    SecondaryStorageVmAllocator allocator = getCurrentAllocator();
    assert (allocator != null);
    List<SecondaryStorageVmVO> runningList =
        _secStorageVmDao.getSecStorageVmListInStates(role, dataCenterId, State.Running);
    if (runningList != null && runningList.size() > 0) {
      if (s_logger.isTraceEnabled()) {
        s_logger.trace("Running secondary storage vm pool size : " + runningList.size());
        for (SecondaryStorageVmVO secStorageVm : runningList) {
          s_logger.trace("Running secStorageVm instance : " + secStorageVm.getHostName());
        }
      }

      Map<Long, Integer> loadInfo = new HashMap<Long, Integer>();

      return allocator.allocSecondaryStorageVm(runningList, loadInfo, dataCenterId);
    } else {
      if (s_logger.isTraceEnabled()) {
        s_logger.trace("Empty running secStorageVm pool for now in data center : " + dataCenterId);
      }
    }
    return null;
  }
  @Override
  public boolean generateVMSetupCommand(Long ssAHostId) {
    HostVO ssAHost = _hostDao.findById(ssAHostId);
    if (ssAHost.getType() != Host.Type.SecondaryStorageVM) {
      return false;
    }
    SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName());
    if (secStorageVm == null) {
      s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist");
      return false;
    }

    SecStorageVMSetupCommand setupCmd = new SecStorageVMSetupCommand();
    if (_allowedInternalSites != null) {
      List<String> allowedCidrs = new ArrayList<String>();
      String[] cidrs = _allowedInternalSites.split(",");
      for (String cidr : cidrs) {
        if (NetUtils.isValidCIDR(cidr) || NetUtils.isValidIp(cidr)) {
          allowedCidrs.add(cidr);
        }
      }
      List<? extends Nic> nics =
          _networkMgr.getNicsForTraffic(secStorageVm.getId(), TrafficType.Management);
      Nic privateNic = nics.get(0);
      String privateCidr =
          NetUtils.ipAndNetMaskToCidr(privateNic.getIp4Address(), privateNic.getNetmask());
      String publicCidr =
          NetUtils.ipAndNetMaskToCidr(
              secStorageVm.getPublicIpAddress(), secStorageVm.getPublicNetmask());
      if (NetUtils.isNetworkAWithinNetworkB(privateCidr, publicCidr)
          || NetUtils.isNetworkAWithinNetworkB(publicCidr, privateCidr)) {
        s_logger.info(
            "private and public interface overlaps, add a default route through private interface. privateCidr: "
                + privateCidr
                + ", publicCidr: "
                + publicCidr);
        allowedCidrs.add(NetUtils.ALL_CIDRS);
      }
      setupCmd.setAllowedInternalSites(allowedCidrs.toArray(new String[allowedCidrs.size()]));
    }
    String copyPasswd = _configDao.getValue("secstorage.copy.password");
    setupCmd.setCopyPassword(copyPasswd);
    setupCmd.setCopyUserName(TemplateConstants.DEFAULT_HTTP_AUTH_USER);
    Answer answer = _agentMgr.easySend(ssAHostId, setupCmd);
    if (answer != null && answer.getResult()) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug("Successfully programmed http auth into " + secStorageVm.getHostName());
      }
      return true;
    } else {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "failed to program http auth into secondary storage vm : "
                + secStorageVm.getHostName());
      }
      return false;
    }
  }
  public SecondaryStorageVmVO assignSecStorageVmFromStoppedPool(
      long dataCenterId, SecondaryStorageVm.Role role) {
    List<SecondaryStorageVmVO> l =
        _secStorageVmDao.getSecStorageVmListInStates(
            role, dataCenterId, State.Starting, State.Stopped, State.Migrating);
    if (l != null && l.size() > 0) {
      return l.get(0);
    }

    return null;
  }
  @Override
  public boolean destroySecStorageVm(long vmId) {
    SecondaryStorageVmVO ssvm = _secStorageVmDao.findById(vmId);

    try {
      return _itMgr.expunge(ssvm, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount());
    } catch (ResourceUnavailableException e) {
      s_logger.warn("Unable to expunge " + ssvm, e);
      return false;
    }
  }
  @Override
  public boolean stopSecStorageVm(long secStorageVmId) {
    SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
    if (secStorageVm == null) {
      String msg =
          "Stopping secondary storage vm failed: secondary storage vm "
              + secStorageVmId
              + " no longer exists";
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(msg);
      }
      return false;
    }
    try {
      if (secStorageVm.getHostId() != null) {
        GlobalLock secStorageVmLock =
            GlobalLock.getInternLock(getSecStorageVmLockName(secStorageVm.getId()));
        try {
          if (secStorageVmLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) {
            try {
              boolean result =
                  _itMgr.stop(
                      secStorageVm, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount());
              if (result) {}

              return result;
            } finally {
              secStorageVmLock.unlock();
            }
          } else {
            String msg = "Unable to acquire secondary storage vm lock : " + secStorageVm.toString();
            s_logger.debug(msg);
            return false;
          }
        } finally {
          secStorageVmLock.releaseRef();
        }
      }

      // vm was already stopped, return true
      return true;
    } catch (ResourceUnavailableException e) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Stopping secondary storage vm "
                + secStorageVm.getHostName()
                + " faled : exception "
                + e.toString());
      }
      return false;
    }
  }
 @Override
 public SecondaryStorageVmVO startSecStorageVm(long secStorageVmId) {
   try {
     SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
     Account systemAcct = _accountMgr.getSystemAccount();
     User systemUser = _accountMgr.getSystemUser();
     return _itMgr.start(secStorageVm, null, systemUser, systemAcct);
   } catch (StorageUnavailableException e) {
     s_logger.warn("Exception while trying to start secondary storage vm", e);
     return null;
   } catch (InsufficientCapacityException e) {
     s_logger.warn("Exception while trying to start secondary storage vm", e);
     return null;
   } catch (ResourceUnavailableException e) {
     s_logger.warn("Exception while trying to start secondary storage vm", e);
     return null;
   } catch (Exception e) {
     s_logger.warn("Exception while trying to start secondary storage vm", e);
     return null;
   }
 }
  @Override
  public boolean rebootSecStorageVm(long secStorageVmId) {
    final SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);

    if (secStorageVm == null || secStorageVm.getState() == State.Destroyed) {
      return false;
    }

    if (secStorageVm.getState() == State.Running && secStorageVm.getHostId() != null) {
      final RebootCommand cmd = new RebootCommand(secStorageVm.getInstanceName());
      final Answer answer = _agentMgr.easySend(secStorageVm.getHostId(), cmd);

      if (answer != null && answer.getResult()) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("Successfully reboot secondary storage vm " + secStorageVm.getHostName());
        }

        SubscriptionMgr.getInstance()
            .notifySubscribers(
                ALERT_SUBJECT,
                this,
                new SecStorageVmAlertEventArgs(
                    SecStorageVmAlertEventArgs.SSVM_REBOOTED,
                    secStorageVm.getDataCenterIdToDeployIn(),
                    secStorageVm.getId(),
                    secStorageVm,
                    null));

        return true;
      } else {
        String msg = "Rebooting Secondary Storage VM failed - " + secStorageVm.getHostName();
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(msg);
        }
        return false;
      }
    } else {
      return startSecStorageVm(secStorageVmId) != null;
    }
  }
  private String generateCopyUrl(HostVO sourceServer, VMTemplateHostVO srcTmpltHost) {
    List<SecondaryStorageVmVO> ssVms =
        _secStorageVmDao.getSecStorageVmListInStates(
            SecondaryStorageVm.Role.templateProcessor,
            sourceServer.getDataCenterId(),
            State.Running);
    if (ssVms.size() > 0) {
      SecondaryStorageVmVO ssVm = ssVms.get(0);
      if (ssVm.getPublicIpAddress() == null) {
        s_logger.warn("A running secondary storage vm has a null public ip?");
        return null;
      }
      return generateCopyUrl(
          ssVm.getPublicIpAddress(), sourceServer.getParent(), srcTmpltHost.getInstallPath());
    }

    VMTemplateVO tmplt = _templateDao.findById(srcTmpltHost.getTemplateId());
    HypervisorType hyperType = tmplt.getHypervisorType();
    /*No secondary storage vm yet*/
    if (hyperType != null && hyperType == HypervisorType.KVM) {
      return "file://" + sourceServer.getParent() + "/" + srcTmpltHost.getInstallPath();
    }
    return null;
  }
 @Override
 public SecondaryStorageVmVO findById(long id) {
   return _secStorageVmDao.findById(id);
 }
 SecondaryStorageVmVO getSSVMfromHost(HostVO ssAHost) {
   if (ssAHost.getType() == Host.Type.SecondaryStorageVM) {
     return _secStorageVmDao.findByInstanceName(ssAHost.getName());
   }
   return null;
 }
 @Override
 public SecondaryStorageVmVO persist(SecondaryStorageVmVO vm) {
   return _secStorageVmDao.persist(vm);
 }
  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;
  }
  public SecondaryStorageVmVO startNew(long dataCenterId, SecondaryStorageVm.Role role) {

    if (!isSecondaryStorageVmRequired(dataCenterId)) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Secondary storage vm not required in zone " + dataCenterId + " acc. to zone config");
      }
      return null;
    }
    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Assign secondary storage vm from a newly started instance for request from data center : "
              + dataCenterId);
    }

    Map<String, Object> context = createSecStorageVmInstance(dataCenterId, role);

    long secStorageVmId = (Long) context.get("secStorageVmId");
    if (secStorageVmId == 0) {
      if (s_logger.isTraceEnabled()) {
        s_logger.trace(
            "Creating secondary storage vm instance failed, data center id : " + dataCenterId);
      }

      return null;
    }

    SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
    // SecondaryStorageVmVO secStorageVm =
    // allocSecStorageVmStorage(dataCenterId, secStorageVmId);
    if (secStorageVm != null) {
      SubscriptionMgr.getInstance()
          .notifySubscribers(
              ALERT_SUBJECT,
              this,
              new SecStorageVmAlertEventArgs(
                  SecStorageVmAlertEventArgs.SSVM_CREATED,
                  dataCenterId,
                  secStorageVmId,
                  secStorageVm,
                  null));
      return secStorageVm;
    } else {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Unable to allocate secondary storage vm storage, remove the secondary storage vm record from DB, secondary storage vm id: "
                + secStorageVmId);
      }

      SubscriptionMgr.getInstance()
          .notifySubscribers(
              ALERT_SUBJECT,
              this,
              new SecStorageVmAlertEventArgs(
                  SecStorageVmAlertEventArgs.SSVM_CREATE_FAILURE,
                  dataCenterId,
                  secStorageVmId,
                  null,
                  "Unable to allocate storage"));
    }
    return null;
  }
  @Override
  public boolean generateFirewallConfiguration(Long ssAHostId) {
    if (ssAHostId == null) {
      return true;
    }
    HostVO ssAHost = _hostDao.findById(ssAHostId);
    Long zoneId = ssAHost.getDataCenterId();
    SecondaryStorageVmVO thisSecStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName());

    if (thisSecStorageVm == null) {
      s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist");
      return false;
    }

    List<SecondaryStorageVmVO> alreadyRunning =
        _secStorageVmDao.getSecStorageVmListInStates(
            SecondaryStorageVm.Role.templateProcessor,
            State.Running,
            State.Migrating,
            State.Starting);

    String copyPort =
        _useSSlCopy ? "443" : Integer.toString(TemplateConstants.DEFAULT_TMPLT_COPY_PORT);
    SecStorageFirewallCfgCommand cpc = new SecStorageFirewallCfgCommand();
    SecStorageFirewallCfgCommand thiscpc = new SecStorageFirewallCfgCommand();
    thiscpc.addPortConfig(
        thisSecStorageVm.getPublicIpAddress(),
        copyPort,
        true,
        TemplateConstants.DEFAULT_TMPLT_COPY_INTF);
    for (SecondaryStorageVmVO ssVm : alreadyRunning) {
      if (ssVm.getDataCenterIdToDeployIn() == zoneId) {
        continue;
      }
      if (ssVm.getPublicIpAddress() != null) {
        cpc.addPortConfig(
            ssVm.getPublicIpAddress(), copyPort, true, TemplateConstants.DEFAULT_TMPLT_COPY_INTF);
      }
      if (ssVm.getState() != State.Running) {
        continue;
      }
      String instanceName = ssVm.getInstanceName();
      HostVO host = _hostDao.findByName(instanceName);
      if (host == null) {
        continue;
      }
      Answer answer = _agentMgr.easySend(host.getId(), thiscpc);
      if (answer != null && answer.getResult()) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("Successfully programmed firewall rules into " + ssVm.getHostName());
        }
      } else {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "failed to program firewall rules into secondary storage vm : " + ssVm.getHostName());
        }
        return false;
      }
    }

    Answer answer = _agentMgr.easySend(ssAHostId, cpc);
    if (answer != null && answer.getResult()) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Successfully programmed firewall rules into " + thisSecStorageVm.getHostName());
      }
    } else {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "failed to program firewall rules into secondary storage vm : "
                + thisSecStorageVm.getHostName());
      }
      return false;
    }

    return true;
  }
  @Override
  public boolean generateSetupCommand(Long ssHostId) {
    HostVO cssHost = _hostDao.findById(ssHostId);
    Long zoneId = cssHost.getDataCenterId();
    if (cssHost.getType() == Host.Type.SecondaryStorageVM) {

      SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findByInstanceName(cssHost.getName());
      if (secStorageVm == null) {
        s_logger.warn("secondary storage VM " + cssHost.getName() + " doesn't exist");
        return false;
      }

      List<HostVO> ssHosts = _hostDao.listSecondaryStorageHosts(zoneId);
      for (HostVO ssHost : ssHosts) {
        String secUrl = ssHost.getStorageUrl();
        SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl);

        Answer answer = _agentMgr.easySend(ssHostId, setupCmd);
        if (answer != null && answer.getResult()) {
          SecStorageSetupAnswer an = (SecStorageSetupAnswer) answer;
          ssHost.setParent(an.get_dir());
          _hostDao.update(ssHost.getId(), ssHost);
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                "Successfully programmed secondary storage "
                    + ssHost.getName()
                    + " in secondary storage VM "
                    + secStorageVm.getInstanceName());
          }
        } else {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                "Successfully programmed secondary storage "
                    + ssHost.getName()
                    + " in secondary storage VM "
                    + secStorageVm.getInstanceName());
          }
          return false;
        }
      }
    } else if (cssHost.getType() == Host.Type.SecondaryStorage) {
      List<SecondaryStorageVmVO> alreadyRunning =
          _secStorageVmDao.getSecStorageVmListInStates(
              SecondaryStorageVm.Role.templateProcessor, zoneId, State.Running);
      String secUrl = cssHost.getStorageUrl();
      SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl);
      for (SecondaryStorageVmVO ssVm : alreadyRunning) {
        HostVO host = _hostDao.findByName(ssVm.getInstanceName());
        Answer answer = _agentMgr.easySend(host.getId(), setupCmd);
        if (answer != null && answer.getResult()) {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                "Successfully programmed secondary storage "
                    + host.getName()
                    + " in secondary storage VM "
                    + ssVm.getInstanceName());
          }
        } else {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                "Successfully programmed secondary storage "
                    + host.getName()
                    + " in secondary storage VM "
                    + ssVm.getInstanceName());
          }
          return false;
        }
      }
    }
    return true;
  }