From 5d262d7b5901faeae715527084ffa86ba400a2e5 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Thu, 26 Dec 2013 12:39:39 -0800 Subject: [PATCH] CLOUDSTACK-5648:CopyTemplate and CopyISO across zones fails after NFS migration to S3. --- .../user/template/CopyTemplateCmd.java | 5 +- .../com/cloud/template/TemplateManager.java | 2 + .../datastore/db/TemplateDataStoreDao.java | 2 + .../image/db/TemplateDataStoreDaoImpl.java | 9 ++- .../cloud/template/TemplateManagerImpl.java | 55 +++++++++++++------ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java index 78bfc186d1c..87f94f72aa1 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/CopyTemplateCmd.java @@ -59,8 +59,7 @@ public class CopyTemplateCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.SOURCE_ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, - required = true, - description = "ID of the zone the template is currently hosted on.") + description = "ID of the zone the template is currently hosted on. If not specified and template is cross-zone, then we will sync this template to region wide image store.") private Long sourceZoneId; ///////////////////////////////////////////////////// @@ -137,7 +136,7 @@ public class CopyTemplateCmd extends BaseAsyncCmd { } response.setResponseName(getCommandName()); - this.setResponseObject(response); + setResponseObject(response); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to copy template"); } diff --git a/engine/components-api/src/com/cloud/template/TemplateManager.java b/engine/components-api/src/com/cloud/template/TemplateManager.java index 83fedcd89a8..0a07f6b4a3d 100755 --- a/engine/components-api/src/com/cloud/template/TemplateManager.java +++ b/engine/components-api/src/com/cloud/template/TemplateManager.java @@ -101,6 +101,8 @@ public interface TemplateManager { DataStore getImageStore(long zoneId, long tmpltId); + DataStore getImageStore(long tmpltId); + Long getTemplateSize(long templateId, long zoneId); DataStore getImageStore(String storeUuid, Long zoneId); diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java index e292a20e6d3..ab458895e46 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreDao.java @@ -59,6 +59,8 @@ public interface TemplateDataStoreDao extends GenericDao listByTemplate(long templateId); diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java index be0262e0a53..d4b0445be7e 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/TemplateDataStoreDaoImpl.java @@ -350,15 +350,20 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase sc = templateRoleSearch.create(); sc.setParameters("template_id", templateId); - sc.setParameters("store_role", DataStoreRole.ImageCache); + sc.setParameters("store_role", role); sc.setParameters("destroyed", false); sc.setParameters("state", ObjectInDataStoreStateMachine.State.Ready); return findOneIncludingRemovedBy(sc); } + @Override + public TemplateDataStoreVO findReadyOnCache(long templateId) { + return findReadyByTemplate(templateId, DataStoreRole.ImageCache); + } + @Override public List listOnCache(long templateId) { SearchCriteria sc = templateRoleSearch.create(); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index accb1812d2f..9cde1a544fd 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -689,38 +689,47 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Account caller = CallContext.current().getCallingAccount(); // Verify parameters - if (sourceZoneId.equals(destZoneId)) { - throw new InvalidParameterValueException("Please specify different source and destination zones."); - } - - DataCenterVO sourceZone = _dcDao.findById(sourceZoneId); - if (sourceZone == null) { - throw new InvalidParameterValueException("Please specify a valid source zone."); - } - - DataCenterVO dstZone = _dcDao.findById(destZoneId); - if (dstZone == null) { - throw new InvalidParameterValueException("Please specify a valid destination zone."); - } - VMTemplateVO template = _tmpltDao.findById(templateId); if (template == null || template.getRemoved() != null) { throw new InvalidParameterValueException("Unable to find template with id"); } - DataStore srcSecStore = getImageStore(sourceZoneId, templateId); + DataStore srcSecStore = null; + if (sourceZoneId != null) { + // template is on zone-wide secondary storage + srcSecStore = getImageStore(sourceZoneId, templateId); + } else { + // template is on region store + srcSecStore = getImageStore(templateId); + } + if (srcSecStore == null) { - throw new InvalidParameterValueException("There is no template " + templateId + " in zone " + sourceZoneId); + throw new InvalidParameterValueException("There is no template " + templateId + " ready on image store."); } if (template.isCrossZones()) { - //TODO: we may need UI still enable CopyTemplate in case of cross zone template to trigger sync to region store. // sync template from cache store to region store if it is not there, for cases where we are going to migrate existing NFS to S3. _tmpltSvr.syncTemplateToRegionStore(templateId, srcSecStore); s_logger.debug("Template " + templateId + " is cross-zone, don't need to copy"); return template; } + if (sourceZoneId != null) { + if (sourceZoneId.equals(destZoneId)) { + throw new InvalidParameterValueException("Please specify different source and destination zones."); + } + + DataCenterVO sourceZone = _dcDao.findById(sourceZoneId); + if (sourceZone == null) { + throw new InvalidParameterValueException("Please specify a valid source zone."); + } + } + + DataCenterVO dstZone = _dcDao.findById(destZoneId); + if (dstZone == null) { + throw new InvalidParameterValueException("Please specify a valid destination zone."); + } + DataStore dstSecStore = getImageStore(destZoneId, templateId); if (dstSecStore != null) { s_logger.debug("There is template " + templateId + " in secondary storage " + dstSecStore.getName() + " in zone " + destZoneId + " , don't need to copy"); @@ -1692,6 +1701,18 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return null; } + // get the region wide image store where a template is READY on, + // just pick one is enough. + @Override + public DataStore getImageStore(long tmpltId) { + TemplateDataStoreVO tmpltStore = _tmplStoreDao.findReadyByTemplate(tmpltId, DataStoreRole.Image); + if (tmpltStore != null) { + return _dataStoreMgr.getDataStore(tmpltStore.getDataStoreId(), DataStoreRole.Image); + } + + return null; + } + @Override public Long getTemplateSize(long templateId, long zoneId) { TemplateDataStoreVO templateStoreRef = _tmplStoreDao.findByTemplateZoneDownloadStatus(templateId, zoneId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED);