Beispiel #1
0
  @Override
  @SuppressWarnings("rawtypes")
  public String handleRequest(Map params, String responseType, StringBuffer auditTrailSb)
      throws ServerApiException {
    String response = null;
    String[] command = null;

    try {
      command = (String[]) params.get("command");
      if (command == null) {
        s_logger.error("invalid request, no command sent");
        if (s_logger.isTraceEnabled()) {
          s_logger.trace("dumping request parameters");
          for (Object key : params.keySet()) {
            String keyStr = (String) key;
            String[] value = (String[]) params.get(key);
            s_logger.trace(
                "   key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0]));
          }
        }
        throw new ServerApiException(
            ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent");
      } else {
        Map<String, String> paramMap = new HashMap<String, String>();
        Set keys = params.keySet();
        Iterator keysIter = keys.iterator();
        while (keysIter.hasNext()) {
          String key = (String) keysIter.next();
          if ("command".equalsIgnoreCase(key)) {
            continue;
          }
          String[] value = (String[]) params.get(key);
          // fail if parameter value contains ASCII control (non-printable) characters
          if (value[0] != null) {
            Pattern pattern = Pattern.compile(controlCharacters);
            Matcher matcher = pattern.matcher(value[0]);
            if (matcher.find()) {
              throw new ServerApiException(
                  ApiErrorCode.PARAM_ERROR,
                  "Received value "
                      + value[0]
                      + " for parameter "
                      + key
                      + " is invalid, contains illegal ASCII non-printable characters");
            }
          }
          paramMap.put(key, value[0]);
        }

        Class<?> cmdClass = getCmdClass(command[0]);
        if (cmdClass != null) {
          BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance();
          cmdObj = ComponentContext.inject(cmdObj);
          cmdObj.configure();
          cmdObj.setFullUrlParams(paramMap);
          cmdObj.setResponseType(responseType);
          cmdObj.setHttpMethod(paramMap.get("httpmethod").toString());

          // This is where the command is either serialized, or directly dispatched
          response = queueCommand(cmdObj, paramMap);
          buildAuditTrail(auditTrailSb, command[0], response);
        } else {
          if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) {
            String errorString =
                "Unknown API command: " + ((command == null) ? "null" : command[0]);
            s_logger.warn(errorString);
            auditTrailSb.append(" " + errorString);
            throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, errorString);
          }
        }
      }
    } catch (InvalidParameterValueException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex);
    } catch (IllegalArgumentException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex);
    } catch (PermissionDeniedException ex) {
      ArrayList<ExceptionProxyObject> idList = ex.getIdProxyList();
      if (idList != null) {
        StringBuffer buf = new StringBuffer();
        for (ExceptionProxyObject obj : idList) {
          buf.append(obj.getDescription());
          buf.append(":");
          buf.append(obj.getUuid());
          buf.append(" ");
        }
        s_logger.info(
            "PermissionDenied: " + ex.getMessage() + " on objs: [" + buf.toString() + "]");
      } else {
        s_logger.info("PermissionDenied: " + ex.getMessage());
      }
      throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, ex.getMessage(), ex);
    } catch (AccountLimitException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.ACCOUNT_RESOURCE_LIMIT_ERROR, ex.getMessage(), ex);
    } catch (InsufficientCapacityException ex) {
      s_logger.info(ex.getMessage());
      String errorMsg = ex.getMessage();
      if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg, ex);
    } catch (ResourceAllocationException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage(), ex);
    } catch (ResourceUnavailableException ex) {
      s_logger.info(ex.getMessage());
      String errorMsg = ex.getMessage();
      if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, errorMsg, ex);
    } catch (ServerApiException ex) {
      s_logger.info(ex.getDescription());
      throw ex;
    } catch (Exception ex) {
      s_logger.error(
          "unhandled exception executing api command: " + ((command == null) ? "null" : command[0]),
          ex);
      String errorMsg = ex.getMessage();
      if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg, ex);
    }

    return response;
  }
  @SuppressWarnings("rawtypes")
  public String handleRequest(
      Map params, boolean decode, String responseType, StringBuffer auditTrailSb)
      throws ServerApiException {
    String response = null;
    String[] command = null;
    try {
      command = (String[]) params.get("command");
      if (command == null) {
        s_logger.error("invalid request, no command sent");
        if (s_logger.isTraceEnabled()) {
          s_logger.trace("dumping request parameters");
          for (Object key : params.keySet()) {
            String keyStr = (String) key;
            String[] value = (String[]) params.get(key);
            s_logger.trace(
                "   key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0]));
          }
        }
        throw new ServerApiException(
            ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent");
      } else {
        Map<String, String> paramMap = new HashMap<String, String>();
        Set keys = params.keySet();
        Iterator keysIter = keys.iterator();
        while (keysIter.hasNext()) {
          String key = (String) keysIter.next();
          if ("command".equalsIgnoreCase(key)) {
            continue;
          }
          String[] value = (String[]) params.get(key);

          String decodedValue = null;
          if (decode) {
            try {
              decodedValue = URLDecoder.decode(value[0], "UTF-8");
            } catch (UnsupportedEncodingException usex) {
              s_logger.warn(key + " could not be decoded, value = " + value[0]);
              throw new ServerApiException(
                  ApiErrorCode.PARAM_ERROR,
                  key + " could not be decoded, received value " + value[0]);
            } catch (IllegalArgumentException iae) {
              s_logger.warn(key + " could not be decoded, value = " + value[0]);
              throw new ServerApiException(
                  ApiErrorCode.PARAM_ERROR,
                  key
                      + " could not be decoded, received value "
                      + value[0]
                      + " which contains illegal characters eg.%");
            }
          } else {
            decodedValue = value[0];
          }
          paramMap.put(key, decodedValue);
        }

        Class<?> cmdClass = getCmdClass(command[0]);
        if (cmdClass != null) {
          BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance();
          cmdObj.setFullUrlParams(paramMap);
          cmdObj.setResponseType(responseType);
          // This is where the command is either serialized, or directly dispatched
          response = queueCommand(cmdObj, paramMap);
          buildAuditTrail(auditTrailSb, command[0], response);
        } else {
          if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) {
            String errorString =
                "Unknown API command: " + ((command == null) ? "null" : command[0]);
            s_logger.warn(errorString);
            auditTrailSb.append(" " + errorString);
            throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, errorString);
          }
        }
      }
    } catch (InvalidParameterValueException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex);
    } catch (IllegalArgumentException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex);
    } catch (PermissionDeniedException ex) {
      ArrayList<String> idList = ex.getIdProxyList();
      if (idList != null) {
        s_logger.info(
            "PermissionDenied: "
                + ex.getMessage()
                + " on uuids: ["
                + StringUtils.listToCsvTags(idList)
                + "]");
      } else {
        s_logger.info("PermissionDenied: " + ex.getMessage());
      }
      throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, ex.getMessage(), ex);
    } catch (AccountLimitException ex) {
      s_logger.info(ex.getMessage());
      throw new ServerApiException(ApiErrorCode.ACCOUNT_RESOURCE_LIMIT_ERROR, ex.getMessage(), ex);
    } catch (InsufficientCapacityException ex) {
      s_logger.info(ex.getMessage());
      String errorMsg = ex.getMessage();
      if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg, ex);
    } catch (ResourceAllocationException ex) {
      s_logger.info(ex.getMessage());
      String errorMsg = ex.getMessage();
      if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, errorMsg, ex);
    } catch (ResourceUnavailableException ex) {
      s_logger.info(ex.getMessage());
      String errorMsg = ex.getMessage();
      if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, errorMsg, ex);
    } catch (AsyncCommandQueued ex) {
      s_logger.error(
          "unhandled exception executing api command: " + ((command == null) ? "null" : command[0]),
          ex);
      throw new ServerApiException(
          ApiErrorCode.INTERNAL_ERROR, "Internal server error, unable to execute request.");
    } catch (ServerApiException ex) {
      s_logger.info(ex.getDescription());
      throw ex;
    } catch (Exception ex) {
      s_logger.error(
          "unhandled exception executing api command: " + ((command == null) ? "null" : command[0]),
          ex);
      String errorMsg = ex.getMessage();
      if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) {
        // hide internal details to non-admin user for security reason
        errorMsg = BaseCmd.USER_ERROR_MESSAGE;
      }
      throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg, ex);
    }

    return response;
  }
  @Override
  public void handleTemplateSync(HostVO ssHost) {
    if (ssHost == null) {
      s_logger.warn("Huh? ssHost is null");
      return;
    }
    long sserverId = ssHost.getId();
    long zoneId = ssHost.getDataCenterId();
    if (!(ssHost.getType() == Host.Type.SecondaryStorage
        || ssHost.getType() == Host.Type.LocalSecondaryStorage)) {
      s_logger.warn("Huh? Agent id " + sserverId + " is not secondary storage host");
      return;
    }

    Map<String, TemplateInfo> templateInfos = listTemplate(ssHost);
    if (templateInfos == null) {
      return;
    }

    Set<VMTemplateVO> toBeDownloaded = new HashSet<VMTemplateVO>();
    List<VMTemplateVO> allTemplates = _templateDao.listAllInZone(zoneId);
    List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
    List<VMTemplateVO> defaultBuiltin = _templateDao.listDefaultBuiltinTemplates();

    if (rtngTmplts != null) {
      for (VMTemplateVO rtngTmplt : rtngTmplts) {
        if (!allTemplates.contains(rtngTmplt)) {
          allTemplates.add(rtngTmplt);
        }
      }
    }

    if (defaultBuiltin != null) {
      for (VMTemplateVO builtinTmplt : defaultBuiltin) {
        if (!allTemplates.contains(builtinTmplt)) {
          allTemplates.add(builtinTmplt);
        }
      }
    }

    toBeDownloaded.addAll(allTemplates);

    for (VMTemplateVO tmplt : allTemplates) {
      String uniqueName = tmplt.getUniqueName();
      VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(sserverId, tmplt.getId());
      if (templateInfos.containsKey(uniqueName)) {
        TemplateInfo tmpltInfo = templateInfos.remove(uniqueName);
        toBeDownloaded.remove(tmplt);
        if (tmpltHost != null) {
          s_logger.info(
              "Template Sync found " + tmplt.getName() + " already in the template host table");
          if (tmpltHost.getDownloadState() != Status.DOWNLOADED) {
            tmpltHost.setErrorString("");
          }
          if (tmpltInfo.isCorrupted()) {
            tmpltHost.setDownloadState(Status.DOWNLOAD_ERROR);
            String msg =
                "Template "
                    + tmplt.getName()
                    + ":"
                    + tmplt.getId()
                    + " is corrupted on secondary storage "
                    + tmpltHost.getId();
            tmpltHost.setErrorString(msg);
            s_logger.info("msg");
            if (tmplt.getUrl() == null) {
              msg =
                  "Private Template ("
                      + tmplt
                      + ") with install path "
                      + tmpltInfo.getInstallPath()
                      + "is corrupted, please check in secondary storage: "
                      + tmpltHost.getHostId();
              s_logger.warn(msg);
            } else {
              toBeDownloaded.add(tmplt);
            }

          } else {
            tmpltHost.setDownloadPercent(100);
            tmpltHost.setDownloadState(Status.DOWNLOADED);
            tmpltHost.setInstallPath(tmpltInfo.getInstallPath());
            tmpltHost.setSize(tmpltInfo.getSize());
            tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
            tmpltHost.setLastUpdated(new Date());

            // Skipping limit checks for SYSTEM Account and for the templates created from volumes
            // or snapshots
            // which already got checked and incremented during createTemplate API call.
            if (tmpltInfo.getSize() > 0
                && tmplt.getAccountId() != Account.ACCOUNT_ID_SYSTEM
                && tmplt.getUrl() != null) {
              long accountId = tmplt.getAccountId();
              try {
                _resourceLimitMgr.checkResourceLimit(
                    _accountMgr.getAccount(accountId),
                    com.cloud.configuration.Resource.ResourceType.secondary_storage,
                    tmpltInfo.getSize() - UriUtils.getRemoteSize(tmplt.getUrl()));
              } catch (ResourceAllocationException e) {
                s_logger.warn(e.getMessage());
                _alertMgr.sendAlert(
                    _alertMgr.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
                    ssHost.getDataCenterId(),
                    null,
                    e.getMessage(),
                    e.getMessage());
              } finally {
                _resourceLimitMgr.recalculateResourceCount(
                    accountId,
                    _accountMgr.getAccount(accountId).getDomainId(),
                    com.cloud.configuration.Resource.ResourceType.secondary_storage.getOrdinal());
              }
            }
          }
          _vmTemplateHostDao.update(tmpltHost.getId(), tmpltHost);
        } else {
          tmpltHost =
              new VMTemplateHostVO(
                  sserverId,
                  tmplt.getId(),
                  new Date(),
                  100,
                  Status.DOWNLOADED,
                  null,
                  null,
                  null,
                  tmpltInfo.getInstallPath(),
                  tmplt.getUrl());
          tmpltHost.setSize(tmpltInfo.getSize());
          tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize());
          _vmTemplateHostDao.persist(tmpltHost);
          VMTemplateZoneVO tmpltZoneVO =
              _vmTemplateZoneDao.findByZoneTemplate(zoneId, tmplt.getId());
          if (tmpltZoneVO == null) {
            tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date());
            _vmTemplateZoneDao.persist(tmpltZoneVO);
          } else {
            tmpltZoneVO.setLastUpdated(new Date());
            _vmTemplateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO);
          }
        }

        continue;
      }
      if (tmpltHost != null && tmpltHost.getDownloadState() != Status.DOWNLOADED) {
        s_logger.info(
            "Template Sync did not find "
                + tmplt.getName()
                + " ready on server "
                + sserverId
                + ", will request download to start/resume shortly");

      } else if (tmpltHost == null) {
        s_logger.info(
            "Template Sync did not find "
                + tmplt.getName()
                + " on the server "
                + sserverId
                + ", will request download shortly");
        VMTemplateHostVO templtHost =
            new VMTemplateHostVO(
                sserverId,
                tmplt.getId(),
                new Date(),
                0,
                Status.NOT_DOWNLOADED,
                null,
                null,
                null,
                null,
                tmplt.getUrl());
        _vmTemplateHostDao.persist(templtHost);
        VMTemplateZoneVO tmpltZoneVO = _vmTemplateZoneDao.findByZoneTemplate(zoneId, tmplt.getId());
        if (tmpltZoneVO == null) {
          tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date());
          _vmTemplateZoneDao.persist(tmpltZoneVO);
        } else {
          tmpltZoneVO.setLastUpdated(new Date());
          _vmTemplateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO);
        }
      }
    }

    if (toBeDownloaded.size() > 0) {
      /* Only download templates whose hypervirsor type is in the zone */
      List<HypervisorType> availHypers = _clusterDao.getAvailableHypervisorInZone(zoneId);
      if (availHypers.isEmpty()) {
        /*
         * This is for cloudzone, local secondary storage resource
         * started before cluster created
         */
        availHypers.add(HypervisorType.KVM);
      }
      /* Baremetal need not to download any template */
      availHypers.remove(HypervisorType.BareMetal);
      availHypers.add(HypervisorType.None); // bug 9809: resume ISO
      // download.
      for (VMTemplateVO tmplt : toBeDownloaded) {
        if (tmplt.getUrl() == null) { // If url is null we can't
          // initiate the download
          continue;
        }
        // if this is private template, and there is no record for this
        // template in this sHost, skip
        if (!tmplt.isPublicTemplate() && !tmplt.isFeatured()) {
          VMTemplateHostVO tmpltHost =
              _vmTemplateHostDao.findByHostTemplate(sserverId, tmplt.getId());
          if (tmpltHost == null) {
            continue;
          }
        }
        if (availHypers.contains(tmplt.getHypervisorType())) {
          if (_swiftMgr.isSwiftEnabled()) {
            if (_swiftMgr.isTemplateInstalled(tmplt.getId())) {
              continue;
            }
          }
          s_logger.debug(
              "Template " + tmplt.getName() + " needs to be downloaded to " + ssHost.getName());
          downloadTemplateToStorage(tmplt, ssHost);
        } else {
          s_logger.info(
              "Skipping download of template "
                  + tmplt.getName()
                  + " since we don't have any "
                  + tmplt.getHypervisorType()
                  + " hypervisors");
        }
      }
    }

    for (String uniqueName : templateInfos.keySet()) {
      TemplateInfo tInfo = templateInfos.get(uniqueName);
      List<UserVmVO> userVmUsingIso = _userVmDao.listByIsoId(tInfo.getId());
      // check if there is any Vm using this ISO.
      if (userVmUsingIso == null || userVmUsingIso.isEmpty()) {
        DeleteTemplateCommand dtCommand =
            new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath());
        try {
          _agentMgr.sendToSecStorage(ssHost, dtCommand, null);
        } catch (AgentUnavailableException e) {
          String err =
              "Failed to delete "
                  + tInfo.getTemplateName()
                  + " on secondary storage "
                  + sserverId
                  + " which isn't in the database";
          s_logger.error(err);
          return;
        }

        String description =
            "Deleted template "
                + tInfo.getTemplateName()
                + " on secondary storage "
                + sserverId
                + " since it isn't in the database";
        s_logger.info(description);
      }
    }
  }
  @Override
  public void handleTemplateSync(DataStore store) {
    if (store == null) {
      s_logger.warn("Huh? image store is null");
      return;
    }
    long storeId = store.getId();

    // add lock to make template sync for a data store only be done once
    String lockString = "templatesync.storeId:" + storeId;
    GlobalLock syncLock = GlobalLock.getInternLock(lockString);
    try {
      if (syncLock.lock(3)) {
        try {
          Long zoneId = store.getScope().getScopeId();

          Map<String, TemplateProp> templateInfos = listTemplate(store);
          if (templateInfos == null) {
            return;
          }

          Set<VMTemplateVO> toBeDownloaded = new HashSet<VMTemplateVO>();
          List<VMTemplateVO> allTemplates = null;
          if (zoneId == null) {
            // region wide store
            allTemplates = _templateDao.listAllActive();
          } else {
            // zone wide store
            allTemplates = _templateDao.listAllInZone(zoneId);
          }
          List<VMTemplateVO> rtngTmplts = _templateDao.listAllSystemVMTemplates();
          List<VMTemplateVO> defaultBuiltin = _templateDao.listDefaultBuiltinTemplates();

          if (rtngTmplts != null) {
            for (VMTemplateVO rtngTmplt : rtngTmplts) {
              if (!allTemplates.contains(rtngTmplt)) {
                allTemplates.add(rtngTmplt);
              }
            }
          }

          if (defaultBuiltin != null) {
            for (VMTemplateVO builtinTmplt : defaultBuiltin) {
              if (!allTemplates.contains(builtinTmplt)) {
                allTemplates.add(builtinTmplt);
              }
            }
          }

          toBeDownloaded.addAll(allTemplates);

          for (VMTemplateVO tmplt : allTemplates) {
            String uniqueName = tmplt.getUniqueName();
            TemplateDataStoreVO tmpltStore =
                _vmTemplateStoreDao.findByStoreTemplate(storeId, tmplt.getId());
            if (templateInfos.containsKey(uniqueName)) {
              TemplateProp tmpltInfo = templateInfos.remove(uniqueName);
              toBeDownloaded.remove(tmplt);
              if (tmpltStore != null) {
                s_logger.info("Template Sync found " + uniqueName + " already in the image store");
                if (tmpltStore.getDownloadState() != Status.DOWNLOADED) {
                  tmpltStore.setErrorString("");
                }
                if (tmpltInfo.isCorrupted()) {
                  tmpltStore.setDownloadState(Status.DOWNLOAD_ERROR);
                  String msg =
                      "Template "
                          + tmplt.getName()
                          + ":"
                          + tmplt.getId()
                          + " is corrupted on secondary storage "
                          + tmpltStore.getId();
                  tmpltStore.setErrorString(msg);
                  s_logger.info("msg");
                  if (tmplt.getUrl() == null) {
                    msg =
                        "Private Template ("
                            + tmplt
                            + ") with install path "
                            + tmpltInfo.getInstallPath()
                            + "is corrupted, please check in image store: "
                            + tmpltStore.getDataStoreId();
                    s_logger.warn(msg);
                  } else {
                    s_logger.info(
                        "Removing template_store_ref entry for corrupted template "
                            + tmplt.getName());
                    _vmTemplateStoreDao.remove(tmpltStore.getId());
                    toBeDownloaded.add(tmplt);
                  }

                } else {
                  tmpltStore.setDownloadPercent(100);
                  tmpltStore.setDownloadState(Status.DOWNLOADED);
                  tmpltStore.setState(ObjectInDataStoreStateMachine.State.Ready);
                  tmpltStore.setInstallPath(tmpltInfo.getInstallPath());
                  tmpltStore.setSize(tmpltInfo.getSize());
                  tmpltStore.setPhysicalSize(tmpltInfo.getPhysicalSize());
                  tmpltStore.setLastUpdated(new Date());
                  // update size in vm_template table
                  VMTemplateVO tmlpt = _templateDao.findById(tmplt.getId());
                  tmlpt.setSize(tmpltInfo.getSize());
                  _templateDao.update(tmplt.getId(), tmlpt);

                  // Skipping limit checks for SYSTEM Account and for the templates created from
                  // volumes or snapshots
                  // which already got checked and incremented during createTemplate API call.
                  if (tmpltInfo.getSize() > 0
                      && tmplt.getAccountId() != Account.ACCOUNT_ID_SYSTEM
                      && tmplt.getUrl() != null) {
                    long accountId = tmplt.getAccountId();
                    try {
                      _resourceLimitMgr.checkResourceLimit(
                          _accountMgr.getAccount(accountId),
                          com.cloud.configuration.Resource.ResourceType.secondary_storage,
                          tmpltInfo.getSize() - UriUtils.getRemoteSize(tmplt.getUrl()));
                    } catch (ResourceAllocationException e) {
                      s_logger.warn(e.getMessage());
                      _alertMgr.sendAlert(
                          AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
                          zoneId,
                          null,
                          e.getMessage(),
                          e.getMessage());
                    } finally {
                      _resourceLimitMgr.recalculateResourceCount(
                          accountId,
                          _accountMgr.getAccount(accountId).getDomainId(),
                          com.cloud.configuration.Resource.ResourceType.secondary_storage
                              .getOrdinal());
                    }
                  }
                }
                _vmTemplateStoreDao.update(tmpltStore.getId(), tmpltStore);
              } else {
                tmpltStore =
                    new TemplateDataStoreVO(
                        storeId,
                        tmplt.getId(),
                        new Date(),
                        100,
                        Status.DOWNLOADED,
                        null,
                        null,
                        null,
                        tmpltInfo.getInstallPath(),
                        tmplt.getUrl());
                tmpltStore.setSize(tmpltInfo.getSize());
                tmpltStore.setPhysicalSize(tmpltInfo.getPhysicalSize());
                tmpltStore.setDataStoreRole(store.getRole());
                _vmTemplateStoreDao.persist(tmpltStore);

                // update size in vm_template table
                VMTemplateVO tmlpt = _templateDao.findById(tmplt.getId());
                tmlpt.setSize(tmpltInfo.getSize());
                _templateDao.update(tmplt.getId(), tmlpt);
                associateTemplateToZone(tmplt.getId(), zoneId);
              }
            } else {
              s_logger.info(
                  "Template Sync did not find "
                      + uniqueName
                      + " on image store "
                      + storeId
                      + ", may request download based on available hypervisor types");
              if (tmpltStore != null) {
                if (isRegionStore(store)
                    && tmpltStore.getDownloadState()
                        == VMTemplateStorageResourceAssoc.Status.DOWNLOADED
                    && tmpltStore.getState() == State.Ready
                    && tmpltStore.getInstallPath() == null) {
                  s_logger.info(
                      "Keep fake entry in template store table for migration of previous NFS to object store");
                } else {
                  s_logger.info(
                      "Removing leftover template "
                          + uniqueName
                          + " entry from template store table");
                  // remove those leftover entries
                  _vmTemplateStoreDao.remove(tmpltStore.getId());
                }
              }
            }
          }

          if (toBeDownloaded.size() > 0) {
            /* Only download templates whose hypervirsor type is in the zone */
            List<HypervisorType> availHypers = _clusterDao.getAvailableHypervisorInZone(zoneId);
            if (availHypers.isEmpty()) {
              /*
               * This is for cloudzone, local secondary storage resource
               * started before cluster created
               */
              availHypers.add(HypervisorType.KVM);
            }
            /* Baremetal need not to download any template */
            availHypers.remove(HypervisorType.BareMetal);
            availHypers.add(HypervisorType.None); // bug 9809: resume ISO
            // download.
            for (VMTemplateVO tmplt : toBeDownloaded) {
              if (tmplt.getUrl() == null) { // If url is null we can't
                s_logger.info(
                    "Skip downloading template "
                        + tmplt.getUniqueName()
                        + " since no url is specified.");
                continue;
              }
              // if this is private template, skip sync to a new image store
              if (!tmplt.isPublicTemplate()
                  && !tmplt.isFeatured()
                  && tmplt.getTemplateType() != TemplateType.SYSTEM) {
                s_logger.info(
                    "Skip sync downloading private template "
                        + tmplt.getUniqueName()
                        + " to a new image store");
                continue;
              }

              // if this is a region store, and there is already an DOWNLOADED entry there without
              // install_path information, which
              // means that this is a duplicate entry from migration of previous NFS to staging.
              if (isRegionStore(store)) {
                TemplateDataStoreVO tmpltStore =
                    _vmTemplateStoreDao.findByStoreTemplate(storeId, tmplt.getId());
                if (tmpltStore != null
                    && tmpltStore.getDownloadState()
                        == VMTemplateStorageResourceAssoc.Status.DOWNLOADED
                    && tmpltStore.getState() == State.Ready
                    && tmpltStore.getInstallPath() == null) {
                  s_logger.info("Skip sync template for migration of previous NFS to object store");
                  continue;
                }
              }

              if (availHypers.contains(tmplt.getHypervisorType())) {
                s_logger.info(
                    "Downloading template "
                        + tmplt.getUniqueName()
                        + " to image store "
                        + store.getName());
                associateTemplateToZone(tmplt.getId(), zoneId);
                TemplateInfo tmpl =
                    _templateFactory.getTemplate(tmplt.getId(), DataStoreRole.Image);
                createTemplateAsync(tmpl, store, null);
              } else {
                s_logger.info(
                    "Skip downloading template "
                        + tmplt.getUniqueName()
                        + " since current data center does not have hypervisor "
                        + tmplt.getHypervisorType().toString());
              }
            }
          }

          for (String uniqueName : templateInfos.keySet()) {
            TemplateProp tInfo = templateInfos.get(uniqueName);
            if (_tmpltMgr.templateIsDeleteable(tInfo.getId())) {
              // we cannot directly call deleteTemplateSync here to
              // reuse delete logic since in this case, our db does not have
              // this template at all.
              TemplateObjectTO tmplTO = new TemplateObjectTO();
              tmplTO.setDataStore(store.getTO());
              tmplTO.setPath(tInfo.getInstallPath());
              tmplTO.setId(tInfo.getId());
              DeleteCommand dtCommand = new DeleteCommand(tmplTO);
              EndPoint ep = _epSelector.select(store);
              Answer answer = null;
              if (ep == null) {
                String errMsg =
                    "No remote endpoint to send command, check if host or ssvm is down?";
                s_logger.error(errMsg);
                answer = new Answer(dtCommand, false, errMsg);
              } else {
                answer = ep.sendMessage(dtCommand);
              }
              if (answer == null || !answer.getResult()) {
                s_logger.info("Failed to deleted template at store: " + store.getName());

              } else {
                String description =
                    "Deleted template "
                        + tInfo.getTemplateName()
                        + " on secondary storage "
                        + storeId;
                s_logger.info(description);
              }
            }
          }
        } finally {
          syncLock.unlock();
        }
      } else {
        s_logger.info(
            "Couldn't get global lock on "
                + lockString
                + ", another thread may be doing template sync on data store "
                + storeId
                + " now.");
      }
    } finally {
      syncLock.releaseRef();
    }
  }
  @Override
  public void handleVolumeSync(HostVO ssHost) {
    if (ssHost == null) {
      s_logger.warn("Huh? ssHost is null");
      return;
    }
    long sserverId = ssHost.getId();
    if (!(ssHost.getType() == Host.Type.SecondaryStorage
        || ssHost.getType() == Host.Type.LocalSecondaryStorage)) {
      s_logger.warn("Huh? Agent id " + sserverId + " is not secondary storage host");
      return;
    }

    Map<Long, TemplateInfo> volumeInfos = listVolume(ssHost);
    if (volumeInfos == null) {
      return;
    }

    List<VolumeHostVO> dbVolumes = _volumeHostDao.listBySecStorage(sserverId);
    List<VolumeHostVO> toBeDownloaded = new ArrayList<VolumeHostVO>(dbVolumes);
    for (VolumeHostVO volumeHost : dbVolumes) {
      VolumeVO volume = _volumeDao.findById(volumeHost.getVolumeId());
      // Exists then don't download
      if (volumeInfos.containsKey(volume.getId())) {
        TemplateInfo volInfo = volumeInfos.remove(volume.getId());
        toBeDownloaded.remove(volumeHost);
        s_logger.info(
            "Volume Sync found " + volume.getUuid() + " already in the volume host table");
        if (volumeHost.getDownloadState() != Status.DOWNLOADED) {
          volumeHost.setErrorString("");
        }
        if (volInfo.isCorrupted()) {
          volumeHost.setDownloadState(Status.DOWNLOAD_ERROR);
          String msg = "Volume " + volume.getUuid() + " is corrupted on secondary storage ";
          volumeHost.setErrorString(msg);
          s_logger.info("msg");
          if (volumeHost.getDownloadUrl() == null) {
            msg =
                "Volume ("
                    + volume.getUuid()
                    + ") with install path "
                    + volInfo.getInstallPath()
                    + "is corrupted, please check in secondary storage: "
                    + volumeHost.getHostId();
            s_logger.warn(msg);
          } else {
            toBeDownloaded.add(volumeHost);
          }

        } else { // Put them in right status
          volumeHost.setDownloadPercent(100);
          volumeHost.setDownloadState(Status.DOWNLOADED);
          volumeHost.setInstallPath(volInfo.getInstallPath());
          volumeHost.setSize(volInfo.getSize());
          volumeHost.setPhysicalSize(volInfo.getPhysicalSize());
          volumeHost.setLastUpdated(new Date());
          _volumeHostDao.update(volumeHost.getId(), volumeHost);

          if (volume.getSize() == 0) {
            // Set volume size in volumes table
            volume.setSize(volInfo.getSize());
            _volumeDao.update(volumeHost.getVolumeId(), volume);
          }

          if (volInfo.getSize() > 0) {
            try {
              String url = _volumeHostDao.findByVolumeId(volume.getId()).getDownloadUrl();
              _resourceLimitMgr.checkResourceLimit(
                  _accountMgr.getAccount(volume.getAccountId()),
                  com.cloud.configuration.Resource.ResourceType.secondary_storage,
                  volInfo.getSize() - UriUtils.getRemoteSize(url));
            } catch (ResourceAllocationException e) {
              s_logger.warn(e.getMessage());
              _alertMgr.sendAlert(
                  _alertMgr.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
                  volume.getDataCenterId(),
                  volume.getPodId(),
                  e.getMessage(),
                  e.getMessage());
            } finally {
              _resourceLimitMgr.recalculateResourceCount(
                  volume.getAccountId(),
                  volume.getDomainId(),
                  com.cloud.configuration.Resource.ResourceType.secondary_storage.getOrdinal());
            }
          }
        }
        continue;
      }
      // Volume is not on secondary but we should download.
      if (volumeHost.getDownloadState() != Status.DOWNLOADED) {
        s_logger.info(
            "Volume Sync did not find "
                + volume.getName()
                + " ready on server "
                + sserverId
                + ", will request download to start/resume shortly");
        toBeDownloaded.add(volumeHost);
      }
    }

    // Download volumes which haven't been downloaded yet.
    if (toBeDownloaded.size() > 0) {
      for (VolumeHostVO volumeHost : toBeDownloaded) {
        if (volumeHost.getDownloadUrl() == null) { // If url is null we can't initiate the download
          continue;
        }
        s_logger.debug(
            "Volume "
                + volumeHost.getVolumeId()
                + " needs to be downloaded to "
                + ssHost.getName());
        downloadVolumeToStorage(
            _volumeDao.findById(volumeHost.getVolumeId()),
            ssHost,
            volumeHost.getDownloadUrl(),
            volumeHost.getChecksum(),
            volumeHost.getFormat());
      }
    }

    // Delete volumes which are not present on DB.
    for (Long uniqueName : volumeInfos.keySet()) {
      TemplateInfo vInfo = volumeInfos.get(uniqueName);
      DeleteVolumeCommand dtCommand =
          new DeleteVolumeCommand(ssHost.getStorageUrl(), vInfo.getInstallPath());
      try {
        _agentMgr.sendToSecStorage(ssHost, dtCommand, null);
      } catch (AgentUnavailableException e) {
        String err =
            "Failed to delete "
                + vInfo.getTemplateName()
                + " on secondary storage "
                + sserverId
                + " which isn't in the database";
        s_logger.error(err);
        return;
      }

      String description =
          "Deleted volume "
              + vInfo.getTemplateName()
              + " on secondary storage "
              + sserverId
              + " since it isn't in the database";
      s_logger.info(description);
    }
  }