Fix the flow of deleteTemplateCmd.

This commit is contained in:
Min Chen 2013-04-16 12:03:12 -07:00
parent 593337565e
commit 0da2da852b
15 changed files with 637 additions and 364 deletions

View File

@ -16,17 +16,26 @@
// under the License. // under the License.
package com.cloud.agent.api.storage; package com.cloud.agent.api.storage;
import com.cloud.agent.api.to.DataStoreTO;
public class DeleteTemplateCommand extends ssCommand { public class DeleteTemplateCommand extends ssCommand {
private DataStoreTO store;
private String templatePath; private String templatePath;
private Long templateId;
private Long accountId;
public DeleteTemplateCommand() { public DeleteTemplateCommand() {
} }
public DeleteTemplateCommand(String secUrl, String templatePath) {
public DeleteTemplateCommand(DataStoreTO store, String secUrl, String templatePath, Long templateId, Long accountId) {
this.setSecUrl(secUrl); this.setSecUrl(secUrl);
this.templatePath = templatePath; this.templatePath = templatePath;
this.templateId = templateId;
this.accountId = accountId;
this.store = store;
} }
@Override @Override
@ -37,4 +46,18 @@ public class DeleteTemplateCommand extends ssCommand {
public String getTemplatePath() { public String getTemplatePath() {
return templatePath; return templatePath;
} }
public Long getTemplateId() {
return templateId;
}
public Long getAccountId() {
return accountId;
}
public DataStoreTO getDataStore() {
return store;
}
} }

View File

@ -128,19 +128,16 @@ public class VMTemplateVO implements VirtualMachineTemplate, StateObject<Templat
@Column(name="enable_sshkey") @Column(name="enable_sshkey")
private boolean enableSshKey; private boolean enableSshKey;
@Column(name = "image_data_store_id")
private long imageDataStoreId;
@Column(name = "size") @Column(name = "size")
private Long size; private Long size;
@Column(name = "state") @Column(name = "state")
private TemplateState state; private TemplateState state;
@Column(name="update_count", updatable = true) @Column(name="update_count", updatable = true)
protected long updatedCount; protected long updatedCount;
@Column(name = "updated") @Column(name = "updated")
@Temporal(value = TemporalType.TIMESTAMP) @Temporal(value = TemporalType.TIMESTAMP)
Date updated; Date updated;
@ -489,31 +486,24 @@ public class VMTemplateVO implements VirtualMachineTemplate, StateObject<Templat
public void setEnableSshKey(boolean enable) { public void setEnableSshKey(boolean enable) {
enableSshKey = enable; enableSshKey = enable;
} }
public Long getImageDataStoreId() {
return this.imageDataStoreId;
}
public void setImageDataStoreId(long dataStoreId) {
this.imageDataStoreId = dataStoreId;
}
public void setSize(Long size) { public void setSize(Long size) {
this.size = size; this.size = size;
} }
public Long getSize() { public Long getSize() {
return this.size; return this.size;
} }
public TemplateState getState() { public TemplateState getState() {
return this.state; return this.state;
} }
public long getUpdatedCount() { public long getUpdatedCount() {
return this.updatedCount; return this.updatedCount;
} }
public void incrUpdatedCount() { public void incrUpdatedCount() {
this.updatedCount++; this.updatedCount++;
} }
@ -521,11 +511,11 @@ public class VMTemplateVO implements VirtualMachineTemplate, StateObject<Templat
public void decrUpdatedCount() { public void decrUpdatedCount() {
this.updatedCount--; this.updatedCount--;
} }
public Date getUpdated() { public Date getUpdated() {
return updated; return updated;
} }
public void setUpdated(Date updated) { public void setUpdated(Date updated) {
this.updated = updated; this.updated = updated;
} }

View File

@ -371,7 +371,7 @@ SecondaryStorageResource {
return new Answer(cmd, false, "Swift is not currently support DownloadCommand"); return new Answer(cmd, false, "Swift is not currently support DownloadCommand");
} }
else{ else{
return new Answer(cmd, false, "Unsupport image data store: " + dstore); return new Answer(cmd, false, "Unsupported image data store: " + dstore);
} }
} }
@ -504,6 +504,8 @@ SecondaryStorageResource {
} }
private Answer execute(final DeleteTemplateFromS3Command cmd) { private Answer execute(final DeleteTemplateFromS3Command cmd) {
final S3TO s3 = cmd.getS3(); final S3TO s3 = cmd.getS3();
@ -1318,51 +1320,107 @@ SecondaryStorageResource {
} }
protected Answer execute(final DeleteTemplateCommand cmd) { protected Answer execute(final DeleteTemplateCommand cmd) {
String relativeTemplatePath = cmd.getTemplatePath(); DataStoreTO dstore = cmd.getDataStore();
String parent = getRootDir(cmd); if (dstore instanceof NfsTO) {
String relativeTemplatePath = cmd.getTemplatePath();
String parent = getRootDir(cmd);
if (relativeTemplatePath.startsWith(File.separator)) { if (relativeTemplatePath.startsWith(File.separator)) {
relativeTemplatePath = relativeTemplatePath.substring(1); relativeTemplatePath = relativeTemplatePath.substring(1);
}
if (!parent.endsWith(File.separator)) {
parent += File.separator;
}
String absoluteTemplatePath = parent + relativeTemplatePath;
File tmpltParent = new File(absoluteTemplatePath).getParentFile();
String details = null;
if (!tmpltParent.exists()) {
details = "template parent directory " + tmpltParent.getName() + " doesn't exist";
s_logger.debug(details);
return new Answer(cmd, true, details);
}
File[] tmpltFiles = tmpltParent.listFiles();
if (tmpltFiles == null || tmpltFiles.length == 0) {
details = "No files under template parent directory " + tmpltParent.getName();
s_logger.debug(details);
} else {
boolean found = false;
for (File f : tmpltFiles) {
if (!found && f.getName().equals("template.properties")) {
found = true;
}
if (!f.delete()) {
return new Answer(cmd, false, "Unable to delete file " + f.getName() + " under Template path "
+ relativeTemplatePath);
}
} }
if (!found) {
details = "Can not find template.properties under " + tmpltParent.getName(); if (!parent.endsWith(File.separator)) {
parent += File.separator;
}
String absoluteTemplatePath = parent + relativeTemplatePath;
File tmpltParent = new File(absoluteTemplatePath).getParentFile();
String details = null;
if (!tmpltParent.exists()) {
details = "template parent directory " + tmpltParent.getName() + " doesn't exist";
s_logger.debug(details); s_logger.debug(details);
return new Answer(cmd, true, details);
}
File[] tmpltFiles = tmpltParent.listFiles();
if (tmpltFiles == null || tmpltFiles.length == 0) {
details = "No files under template parent directory " + tmpltParent.getName();
s_logger.debug(details);
} else {
boolean found = false;
for (File f : tmpltFiles) {
if (!found && f.getName().equals("template.properties")) {
found = true;
}
if (!f.delete()) {
return new Answer(cmd, false, "Unable to delete file " + f.getName() + " under Template path " + relativeTemplatePath);
}
}
if (!found) {
details = "Can not find template.properties under " + tmpltParent.getName();
s_logger.debug(details);
}
}
if (!tmpltParent.delete()) {
details = "Unable to delete directory " + tmpltParent.getName() + " under Template path " + relativeTemplatePath;
s_logger.debug(details);
return new Answer(cmd, false, details);
}
return new Answer(cmd, true, null);
}
else if (dstore instanceof S3TO ){
final S3TO s3 = (S3TO)dstore;
final Long accountId = cmd.getAccountId();
final Long templateId = cmd.getTemplateId();
if (accountId == null || (accountId != null && accountId <= 0)) {
final String errorMessage = "No account id specified for S3 template deletion.";
s_logger.error(errorMessage);
return new Answer(cmd, false, errorMessage);
}
if (templateId == null || (templateId != null && templateId <= 0)) {
final String errorMessage = "No template id specified for S3 template deletion.";
s_logger.error(errorMessage);
return new Answer(cmd, false, errorMessage);
}
final String bucket = s3.getBucketName();
try {
S3Utils.deleteDirectory(s3, bucket,
determineS3TemplateDirectory(templateId, accountId));
return new Answer(cmd, true, String.format(
"Deleted template %1%s from bucket %2$s.", templateId,
bucket));
} catch (Exception e) {
final String errorMessage = String
.format("Failed to delete templaet id %1$s from bucket %2$s due to the following error: %3$s",
templateId, bucket, e.getMessage());
s_logger.error(errorMessage, e);
return new Answer(cmd, false, errorMessage);
} }
} }
if (!tmpltParent.delete()) { else if (dstore instanceof SwiftTO){
details = "Unable to delete directory " + tmpltParent.getName() + " under Template path " SwiftTO swift = (SwiftTO)dstore;
+ relativeTemplatePath; String container = "T-" + cmd.getTemplateId();
s_logger.debug(details); String object = "";
return new Answer(cmd, false, details);
try {
String result = swiftDelete(swift, container, object);
if (result != null) {
String errMsg = "failed to delete object " + container + "/" + object + " , err=" + result;
s_logger.warn(errMsg);
return new Answer(cmd, false, errMsg);
}
return new Answer(cmd, true, "success");
} catch (Exception e) {
String errMsg = cmd + " Command failed due to " + e.toString();
s_logger.warn(errMsg, e);
return new Answer(cmd, false, errMsg);
}
}
else{
return new Answer(cmd, false, "Unsupported image data store: " + dstore);
} }
return new Answer(cmd, true, null);
} }
protected Answer execute(final DeleteVolumeCommand cmd) { protected Answer execute(final DeleteVolumeCommand cmd) {

View File

@ -32,11 +32,19 @@ public interface TemplateDataStoreDao extends GenericDao<TemplateDataStoreVO, Lo
public List<TemplateDataStoreVO> listByStoreId(long id); public List<TemplateDataStoreVO> listByStoreId(long id);
public List<TemplateDataStoreVO> listDestroyed(long storeId);
public void deletePrimaryRecordsForStore(long id); public void deletePrimaryRecordsForStore(long id);
List<TemplateDataStoreVO> listByTemplateStore(long templateId, long storeId);
List<TemplateDataStoreVO> listByTemplateStoreStatus(long templateId, long storeId, State... states); List<TemplateDataStoreVO> listByTemplateStoreStatus(long templateId, long storeId, State... states);
List<TemplateDataStoreVO> listByTemplateStoreDownloadStatus(long templateId, long storeId, Status... status); List<TemplateDataStoreVO> listByTemplateStoreDownloadStatus(long templateId, long storeId, Status... status);
TemplateDataStoreVO findByStoreTemplate(long storeId, long templateId); TemplateDataStoreVO findByStoreTemplate(long storeId, long templateId);
TemplateDataStoreVO findByTemplate(long templateId);
List<TemplateDataStoreVO> listByTemplate(long templateId);
} }

View File

@ -28,6 +28,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.image.store.TemplateObject; import org.apache.cloudstack.storage.image.store.TemplateObject;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -50,6 +52,8 @@ public class ImageDataFactoryImpl implements ImageDataFactory {
DataStoreManager storeMgr; DataStoreManager storeMgr;
@Inject @Inject
VMTemplatePoolDao templatePoolDao; VMTemplatePoolDao templatePoolDao;
@Inject
TemplateDataStoreDao templateStoreDao;
@Override @Override
public TemplateInfo getTemplate(long templateId, DataStore store) { public TemplateInfo getTemplate(long templateId, DataStore store) {
VMTemplateVO templ = imageDataDao.findById(templateId); VMTemplateVO templ = imageDataDao.findById(templateId);
@ -77,13 +81,17 @@ public class ImageDataFactoryImpl implements ImageDataFactory {
TemplateObject tmpl = TemplateObject.getTemplate(templ, store); TemplateObject tmpl = TemplateObject.getTemplate(templ, store);
return tmpl; return tmpl;
} }
//TODO: this method is problematic, since one template can be stored in multiple image stores.
// need to see if we can get rid of this method or change to plural format.
@Override @Override
public TemplateInfo getTemplate(long templateId) { public TemplateInfo getTemplate(long templateId) {
VMTemplateVO templ = imageDataDao.findById(templateId); VMTemplateVO templ = imageDataDao.findById(templateId);
if (templ.getImageDataStoreId() == null) { TemplateDataStoreVO tmplStore = templateStoreDao.findByTemplate(templateId);
return this.getTemplate(templateId, null); DataStore store = null;
if ( tmplStore != null ){
store = this.storeMgr.getDataStore(tmplStore.getDataStoreId(), DataStoreRole.Image);
} }
DataStore store = this.storeMgr.getDataStore(templ.getImageDataStoreId(), DataStoreRole.Image);
return this.getTemplate(templateId, store); return this.getTemplate(templateId, store);
} }
@Override @Override

View File

@ -40,6 +40,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
import com.cloud.storage.template.TemplateProp; import com.cloud.storage.template.TemplateProp;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
@ -139,6 +141,28 @@ public class TemplateServiceImpl implements TemplateService {
} }
} }
class DeleteTemplateContext<T> extends AsyncRpcConext<T> {
final TemplateObject template;
final AsyncCallFuture<CommandResult> future;
public DeleteTemplateContext(AsyncCompletionCallback<T> callback, TemplateObject template,
AsyncCallFuture<CommandResult> future) {
super(callback);
this.template = template;
this.future = future;
}
public TemplateObject getTemplate() {
return template;
}
public AsyncCallFuture<CommandResult> getFuture() {
return future;
}
}
@Override @Override
public AsyncCallFuture<CommandResult> createTemplateAsync( public AsyncCallFuture<CommandResult> createTemplateAsync(
TemplateInfo template, DataStore store) { TemplateInfo template, DataStore store) {
@ -361,7 +385,8 @@ public class TemplateServiceImpl implements TemplateService {
List<UserVmVO> userVmUsingIso = _userVmDao.listByIsoId(tInfo.getId()); List<UserVmVO> userVmUsingIso = _userVmDao.listByIsoId(tInfo.getId());
//check if there is any Vm using this ISO. //check if there is any Vm using this ISO.
if (userVmUsingIso == null || userVmUsingIso.isEmpty()) { if (userVmUsingIso == null || userVmUsingIso.isEmpty()) {
DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(store.getUri(), tInfo.getInstallPath()); VMTemplateVO template = _templateDao.findById(tInfo.getId());
DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(store.getTO(), store.getUri(), tInfo.getInstallPath(), template.getId(), template.getAccountId());
try { try {
HostVO ssAhost = _ssvmMgr.pickSsvmHost(store); HostVO ssAhost = _ssvmMgr.pickSsvmHost(store);
_agentMgr.sendToSecStorage(ssAhost, dtCommand, null); _agentMgr.sendToSecStorage(ssAhost, dtCommand, null);
@ -458,7 +483,28 @@ public class TemplateServiceImpl implements TemplateService {
@Override @Override
public AsyncCallFuture<CommandResult> deleteTemplateAsync( public AsyncCallFuture<CommandResult> deleteTemplateAsync(
TemplateInfo template) { TemplateInfo template) {
// TODO Auto-generated method stub TemplateObject to = (TemplateObject) template;
// update template_store_ref status
to.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested);
AsyncCallFuture<CommandResult> future = new AsyncCallFuture<CommandResult>();
DeleteTemplateContext<CommandResult> context = new DeleteTemplateContext<CommandResult>(null, to, future);
AsyncCallbackDispatcher<TemplateServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().deleteTemplateCallback(null, null)).setContext(context);
to.getDataStore().getDriver().deleteAsync(to, caller);
return future;
}
public Void deleteTemplateCallback(AsyncCallbackDispatcher<TemplateServiceImpl, CommandResult> callback, DeleteTemplateContext<CommandResult> context) {
CommandResult result = callback.getResult();
TemplateObject vo = context.getTemplate();
// we can only update state in template_store_ref table
if (result.isSuccess()) {
vo.processEvent(Event.OperationSuccessed);
} else {
vo.processEvent(Event.OperationFailed);
}
context.getFuture().complete(result);
return null; return null;
} }

View File

@ -69,9 +69,6 @@ public class TemplateObject implements TemplateInfo {
return to; return to;
} }
public void setImageStoreId(long id) {
this.imageVO.setImageDataStoreId(id);
}
public void setSize(Long size) { public void setSize(Long size) {
this.imageVO.setSize(size); this.imageVO.setSize(size);
@ -85,7 +82,7 @@ public class TemplateObject implements TemplateInfo {
public DataStore getDataStore() { public DataStore getDataStore() {
return this.dataStore; return this.dataStore;
} }
@Override @Override
public String getUniqueName() { public String getUniqueName() {
return this.imageVO.getUniqueName(); return this.imageVO.getUniqueName();
@ -126,7 +123,7 @@ public class TemplateObject implements TemplateInfo {
if (templateHostVO == null) { if (templateHostVO == null) {
VMTemplateSwiftVO templateSwiftVO = _swiftMgr.findByTmpltId(templateForVmCreation.getId()); VMTemplateSwiftVO templateSwiftVO = _swiftMgr.findByTmpltId(templateForVmCreation.getId());
if (templateSwiftVO != null) { if (templateSwiftVO != null) {
long templateSize = templateSwiftVO.getPhysicalSize(); long templateSize = templateSwiftVO.getPhysicalSize();
if (templateSize == 0) { if (templateSize == 0) {
templateSize = templateSwiftVO.getSize(); templateSize = templateSwiftVO.getSize();
@ -172,7 +169,7 @@ public class TemplateObject implements TemplateInfo {
throw new CloudRuntimeException("Failed to update state" + e.toString()); throw new CloudRuntimeException("Failed to update state" + e.toString());
} }
} }
@Override @Override
public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answer) { public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answer) {
try { try {
@ -182,14 +179,14 @@ public class TemplateObject implements TemplateInfo {
throw new CloudRuntimeException("Failed to update state" + e.toString()); throw new CloudRuntimeException("Failed to update state" + e.toString());
} }
} }
@Override @Override
public DataTO getTO() { public DataTO getTO() {
DataTO to = this.dataStore.getDriver().getTO(this); DataTO to = this.dataStore.getDriver().getTO(this);
if (to == null) { if (to == null) {
to = new TemplateObjectTO(this); to = new TemplateObjectTO(this);
} }
return to; return to;
} }
} }

View File

@ -43,9 +43,11 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase<TemplateDataStoreVO
private static final Logger s_logger = Logger.getLogger(TemplateDataStoreDaoImpl.class); private static final Logger s_logger = Logger.getLogger(TemplateDataStoreDaoImpl.class);
private SearchBuilder<TemplateDataStoreVO> updateStateSearch; private SearchBuilder<TemplateDataStoreVO> updateStateSearch;
private SearchBuilder<TemplateDataStoreVO> storeSearch; private SearchBuilder<TemplateDataStoreVO> storeSearch;
private SearchBuilder<TemplateDataStoreVO> templateSearch;
private SearchBuilder<TemplateDataStoreVO> storeTemplateSearch;
private SearchBuilder<TemplateDataStoreVO> storeTemplateStateSearch; private SearchBuilder<TemplateDataStoreVO> storeTemplateStateSearch;
private SearchBuilder<TemplateDataStoreVO> storeTemplateDownloadStatusSearch; private SearchBuilder<TemplateDataStoreVO> storeTemplateDownloadStatusSearch;
private SearchBuilder<TemplateDataStoreVO> storeTemplateSearch;
@Override @Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@ -57,12 +59,24 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase<TemplateDataStoreVO
storeSearch.and("destroyed", storeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); storeSearch.and("destroyed", storeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
storeSearch.done(); storeSearch.done();
templateSearch = createSearchBuilder();
templateSearch.and("template_id", templateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
templateSearch.and("destroyed", templateSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
templateSearch.done();
updateStateSearch = this.createSearchBuilder(); updateStateSearch = this.createSearchBuilder();
updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ);
updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ);
updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ);
updateStateSearch.done(); updateStateSearch.done();
storeTemplateSearch = createSearchBuilder();
storeTemplateSearch.and("template_id", storeTemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
storeTemplateSearch.and("store_id", storeTemplateSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
storeTemplateSearch.and("destroyed", storeTemplateSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
storeTemplateSearch.done();
storeTemplateStateSearch = createSearchBuilder(); storeTemplateStateSearch = createSearchBuilder();
storeTemplateStateSearch.and("template_id", storeTemplateStateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); storeTemplateStateSearch.and("template_id", storeTemplateStateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
storeTemplateStateSearch.and("store_id", storeTemplateStateSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ); storeTemplateStateSearch.and("store_id", storeTemplateStateSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
@ -133,6 +147,14 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase<TemplateDataStoreVO
return listIncludingRemovedBy(sc); return listIncludingRemovedBy(sc);
} }
@Override
public List<TemplateDataStoreVO> listDestroyed(long id) {
SearchCriteria<TemplateDataStoreVO> sc = storeSearch.create();
sc.setParameters("store_id", id);
sc.setParameters("destroyed", true);
return listIncludingRemovedBy(sc);
}
@Override @Override
public void deletePrimaryRecordsForStore(long id) { public void deletePrimaryRecordsForStore(long id) {
SearchCriteria<TemplateDataStoreVO> sc = storeSearch.create(); SearchCriteria<TemplateDataStoreVO> sc = storeSearch.create();
@ -144,12 +166,22 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase<TemplateDataStoreVO
} }
@Override
public List<TemplateDataStoreVO> listByTemplateStore(long templateId, long storeId) {
SearchCriteria<TemplateDataStoreVO> sc = storeTemplateSearch.create();
sc.setParameters("template_id", templateId);
sc.setParameters("store_id", storeId);
sc.setParameters("destroyed", false);
return search(sc, null);
}
@Override @Override
public List<TemplateDataStoreVO> listByTemplateStoreStatus(long templateId, long storeId, State... states) { public List<TemplateDataStoreVO> listByTemplateStoreStatus(long templateId, long storeId, State... states) {
SearchCriteria<TemplateDataStoreVO> sc = storeTemplateStateSearch.create(); SearchCriteria<TemplateDataStoreVO> sc = storeTemplateStateSearch.create();
sc.setParameters("template_id", templateId); sc.setParameters("template_id", templateId);
sc.setParameters("store_id", storeId); sc.setParameters("store_id", storeId);
sc.setParameters("states", (Object[])states); sc.setParameters("states", (Object[])states);
sc.setParameters("destroyed", false);
return search(sc, null); return search(sc, null);
} }
@ -157,10 +189,11 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase<TemplateDataStoreVO
@Override @Override
public List<TemplateDataStoreVO> listByTemplateStoreDownloadStatus(long templateId, long storeId, Status... status) { public List<TemplateDataStoreVO> listByTemplateStoreDownloadStatus(long templateId, long storeId, Status... status) {
SearchCriteria<TemplateDataStoreVO> sc = storeTemplateStateSearch.create(); SearchCriteria<TemplateDataStoreVO> sc = storeTemplateDownloadStatusSearch.create();
sc.setParameters("template_id", templateId); sc.setParameters("template_id", templateId);
sc.setParameters("store_id", storeId); sc.setParameters("store_id", storeId);
sc.setParameters("downloadState", (Object[])status); sc.setParameters("downloadState", (Object[])status);
sc.setParameters("destroyed", false);
return search(sc, null); return search(sc, null);
} }
@ -173,6 +206,22 @@ public class TemplateDataStoreDaoImpl extends GenericDaoBase<TemplateDataStoreVO
return findOneIncludingRemovedBy(sc); return findOneIncludingRemovedBy(sc);
} }
@Override
public TemplateDataStoreVO findByTemplate(long templateId) {
SearchCriteria<TemplateDataStoreVO> sc = templateSearch.create();
sc.setParameters("template_id", templateId);
sc.setParameters("destroyed", false);
return findOneIncludingRemovedBy(sc);
}
@Override
public List<TemplateDataStoreVO> listByTemplate(long templateId) {
SearchCriteria<TemplateDataStoreVO> sc = templateSearch.create();
sc.setParameters("template_id", templateId);
sc.setParameters("destroyed", false);
return search(sc, null);
}
} }

View File

@ -34,6 +34,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcConext; import org.apache.cloudstack.framework.async.AsyncRpcConext;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.image.ImageStoreDriver; import org.apache.cloudstack.storage.image.ImageStoreDriver;
import org.apache.cloudstack.storage.image.store.ImageStoreImpl; import org.apache.cloudstack.storage.image.store.ImageStoreImpl;
import org.apache.cloudstack.storage.image.store.TemplateObject; import org.apache.cloudstack.storage.image.store.TemplateObject;
@ -44,17 +46,23 @@ import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.DeleteSnapshotBackupCommand; import com.cloud.agent.api.DeleteSnapshotBackupCommand;
import com.cloud.agent.api.storage.DeleteTemplateCommand;
import com.cloud.agent.api.storage.DeleteVolumeCommand; import com.cloud.agent.api.storage.DeleteVolumeCommand;
import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.SwiftTO; import com.cloud.agent.api.to.SwiftTO;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.storage.DataStoreRole; import com.cloud.storage.DataStoreRole;
import com.cloud.storage.RegisterVolumePayload; import com.cloud.storage.RegisterVolumePayload;
import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.SnapshotVO; import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.VMTemplateZoneVO;
@ -68,9 +76,14 @@ import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.dao.VolumeHostDao;
import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.download.DownloadMonitor;
import com.cloud.storage.s3.S3Manager; import com.cloud.storage.s3.S3Manager;
import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.swift.SwiftManager;
import com.cloud.user.Account;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.dao.UserVmDao;
public class CloudStackImageStoreDriverImpl implements ImageStoreDriver { public class CloudStackImageStoreDriverImpl implements ImageStoreDriver {
private static final Logger s_logger = Logger private static final Logger s_logger = Logger
@ -92,6 +105,15 @@ public class CloudStackImageStoreDriverImpl implements ImageStoreDriver {
private SwiftManager _swiftMgr; private SwiftManager _swiftMgr;
@Inject @Inject
private S3Manager _s3Mgr; private S3Manager _s3Mgr;
@Inject AccountDao _accountDao;
@Inject UserVmDao _userVmDao;
@Inject
SecondaryStorageVmManager _ssvmMgr;
@Inject
private AgentManager _agentMgr;
@Inject TemplateDataStoreDao _templateStoreDao;
@Override @Override
public String grantAccess(DataObject data, EndPoint ep) { public String grantAccess(DataObject data, EndPoint ep) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
@ -189,6 +211,60 @@ public class CloudStackImageStoreDriverImpl implements ImageStoreDriver {
private void deleteTemplate(DataObject data, AsyncCompletionCallback<CommandResult> callback) { private void deleteTemplate(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
TemplateObject templateObj = (TemplateObject) data;
VMTemplateVO template = templateObj.getImage();
ImageStoreImpl store = (ImageStoreImpl) templateObj.getDataStore();
long storeId = store.getId();
Long sZoneId = store.getDataCenterId();
long templateId = template.getId();
Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId());
String eventType = "";
if (template.getFormat().equals(ImageFormat.ISO)) {
eventType = EventTypes.EVENT_ISO_DELETE;
} else {
eventType = EventTypes.EVENT_TEMPLATE_DELETE;
}
// TODO: need to understand why we need to mark destroyed in
// template_store_ref table here instead of in callback.
// Currently I did that in callback, so I removed previous code to mark template_host_ref
UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null);
List<UserVmVO> userVmUsingIso = _userVmDao.listByIsoId(templateId);
// check if there is any VM using this ISO.
if (userVmUsingIso == null || userVmUsingIso.isEmpty()) {
HostVO ssAhost = _ssvmMgr.pickSsvmHost(store);
// get installpath of this template on image store
TemplateDataStoreVO tmplStore = _templateStoreDao.findByStoreTemplate(storeId, templateId);
String installPath = tmplStore.getInstallPath();
if (installPath != null) {
Answer answer = _agentMgr.sendToSecStorage(ssAhost, new DeleteTemplateCommand(store.getTO(), store.getUri(), installPath, template.getId(), template.getAccountId()));
if (answer == null || !answer.getResult()) {
s_logger.debug("Failed to deleted template at store: " + store.getName());
CommandResult result = new CommandResult();
result.setSucess(false);
result.setResult("Delete template failed");
callback.complete(result);
} else {
s_logger.debug("Deleted template at: " + installPath);
CommandResult result = new CommandResult();
result.setSucess(false);
callback.complete(result);
}
VMTemplateZoneVO templateZone = templateZoneDao.findByZoneTemplate(sZoneId, templateId);
if (templateZone != null) {
templateZoneDao.remove(templateZone.getId());
}
}
}
} }
private void deleteSnapshot(DataObject data, AsyncCompletionCallback<CommandResult> callback) { private void deleteSnapshot(DataObject data, AsyncCompletionCallback<CommandResult> callback) {

View File

@ -1234,69 +1234,80 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
public void cleanupSecondaryStorage(boolean recurring) { public void cleanupSecondaryStorage(boolean recurring) {
try { try {
// Cleanup templates in secondary storage hosts // Cleanup templates in secondary storage hosts
List<HostVO> secondaryStorageHosts = _ssvmMgr List<DataStore> imageStores = this.dataStoreMgr.getImageStoresByScope(new ZoneScope(null));
.listSecondaryStorageHostsInAllZones(); for (DataStore store : imageStores) {
for (HostVO secondaryStorageHost : secondaryStorageHosts) {
try { try {
long hostId = secondaryStorageHost.getId(); long storeId = store.getId();
List<VMTemplateHostVO> destroyedTemplateHostVOs = _vmTemplateHostDao List<TemplateDataStoreVO> destroyedTemplateStoreVOs = this._templateStoreDao.listDestroyed(storeId);
.listDestroyed(hostId);
s_logger.debug("Secondary storage garbage collector found " s_logger.debug("Secondary storage garbage collector found "
+ destroyedTemplateHostVOs.size() + destroyedTemplateStoreVOs.size()
+ " templates to cleanup on secondary storage host: " + " templates to cleanup on secondary storage host: "
+ secondaryStorageHost.getName()); + store.getName());
for (VMTemplateHostVO destroyedTemplateHostVO : destroyedTemplateHostVOs) { for (TemplateDataStoreVO destroyedTemplateStoreVO : destroyedTemplateStoreVOs) {
if (!_tmpltMgr if (!_tmpltMgr
.templateIsDeleteable(destroyedTemplateHostVO)) { .templateIsDeleteable(destroyedTemplateStoreVO)) {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Not deleting template at: " s_logger.debug("Not deleting template at: "
+ destroyedTemplateHostVO); + destroyedTemplateStoreVO);
} }
continue; continue;
} }
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Deleting template host: " s_logger.debug("Deleting template store: "
+ destroyedTemplateHostVO); + destroyedTemplateStoreVO);
} }
String installPath = destroyedTemplateHostVO VMTemplateVO destroyedTemplate = this._vmTemplateDao.findById(destroyedTemplateStoreVO.getTemplateId());
if ( destroyedTemplate == null ){
s_logger.error("Cannot find template : " + destroyedTemplateStoreVO.getTemplateId() + " from template table");
throw new CloudRuntimeException("Template " + destroyedTemplateStoreVO.getTemplateId() + " is found in secondary storage, but not found in template table");
}
String installPath = destroyedTemplateStoreVO
.getInstallPath(); .getInstallPath();
HostVO ssAhost = this._ssvmMgr.pickSsvmHost(store);
if (installPath != null) { if (installPath != null) {
Answer answer = _agentMgr.sendToSecStorage( Answer answer = _agentMgr.sendToSecStorage(
secondaryStorageHost, ssAhost,
new DeleteTemplateCommand( new DeleteTemplateCommand(
secondaryStorageHost store.getTO(),
.getStorageUrl(), store.getUri(),
destroyedTemplateHostVO destroyedTemplateStoreVO
.getInstallPath())); .getInstallPath(),
destroyedTemplate.getId(),
destroyedTemplate.getAccountId()
));
if (answer == null || !answer.getResult()) { if (answer == null || !answer.getResult()) {
s_logger.debug("Failed to delete " s_logger.debug("Failed to delete "
+ destroyedTemplateHostVO + destroyedTemplateStoreVO
+ " due to " + " due to "
+ ((answer == null) ? "answer is null" + ((answer == null) ? "answer is null"
: answer.getDetails())); : answer.getDetails()));
} else { } else {
_vmTemplateHostDao _vmTemplateHostDao
.remove(destroyedTemplateHostVO.getId()); .remove(destroyedTemplateStoreVO.getId());
s_logger.debug("Deleted template at: " s_logger.debug("Deleted template at: "
+ destroyedTemplateHostVO + destroyedTemplateStoreVO
.getInstallPath()); .getInstallPath());
} }
} else { } else {
_vmTemplateHostDao.remove(destroyedTemplateHostVO _vmTemplateHostDao.remove(destroyedTemplateStoreVO
.getId()); .getId());
} }
} }
} catch (Exception e) { } catch (Exception e) {
s_logger.warn( s_logger.warn(
"problem cleaning up templates in secondary storage " "problem cleaning up templates in secondary storage store "
+ secondaryStorageHost, e); + store.getName(), e);
} }
} }
List<HostVO> secondaryStorageHosts = _ssvmMgr
.listSecondaryStorageHostsInAllZones();
// Cleanup snapshot in secondary storage hosts // Cleanup snapshot in secondary storage hosts
for (HostVO secondaryStorageHost : secondaryStorageHosts) { for (HostVO secondaryStorageHost : secondaryStorageHosts) {
try { try {
@ -2037,16 +2048,16 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
if (scope != null) { if (scope != null) {
try { try {
scopeType = Enum.valueOf(ScopeType.class, scope.toUpperCase()); scopeType = Enum.valueOf(ScopeType.class, scope.toUpperCase());
} catch (Exception e) { } catch (Exception e) {
throw new InvalidParameterValueException("invalid scope" + scope); throw new InvalidParameterValueException("invalid scope" + scope);
} }
if (scopeType != ScopeType.ZONE) { if (scopeType != ScopeType.ZONE) {
throw new InvalidParameterValueException("Only zone wide cache storage is supported"); throw new InvalidParameterValueException("Only zone wide cache storage is supported");
} }
} }
if (scopeType == ScopeType.ZONE && dcId == null) { if (scopeType == ScopeType.ZONE && dcId == null) {
throw new InvalidParameterValueException("zone id can't be null, if scope is zone"); throw new InvalidParameterValueException("zone id can't be null, if scope is zone");
} }

View File

@ -38,6 +38,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
@ -180,7 +181,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te
} }
for (DataStore imageStore : imageStores) { for (DataStore imageStore : imageStores) {
AsyncCallFuture<CommandResult> future = this.imageService AsyncCallFuture<CommandResult> future = this.imageService
.createTemplateAsync(this.imageFactory.getTemplate(template.getId()), imageStore); .createTemplateAsync(this.imageFactory.getTemplate(template.getId(), imageStore), imageStore);
try { try {
future.get(); future.get();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -202,123 +203,60 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te
boolean success = true; boolean success = true;
VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); VMTemplateVO template = (VMTemplateVO)profile.getTemplate();
Long zoneId = profile.getZoneId();
Long templateId = template.getId();
String zoneName; // find all eligible image stores for this template
List<HostVO> secondaryStorageHosts; List<DataStore> imageStores = this.templateMgr.getImageStoreByTemplate(template.getId(), profile.getZoneId());
if (!template.isCrossZones() && zoneId != null) { if ( imageStores == null || imageStores.size() == 0 ){
DataCenterVO zone = _dcDao.findById(zoneId); throw new CloudRuntimeException("Unable to find image store to delete template "+ profile.getTemplate());
zoneName = zone.getName(); }
secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId);
} else {
zoneName = "(all zones)";
secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInAllZones();
}
s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); // Make sure the template is downloaded to all found image stores
for (DataStore store : imageStores) {
long storeId = store.getId();
List<TemplateDataStoreVO> templateStores = _tmpltStoreDao.listByTemplateStore(template.getId(), storeId);
for (TemplateDataStoreVO templateStore : templateStores) {
if (templateStore.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
String errorMsg = "Please specify a template that is not currently being downloaded.";
s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + store.getName() + "; cant' delete it.");
throw new CloudRuntimeException(errorMsg);
}
}
}
// Make sure the template is downloaded to all the necessary secondary storage hosts
for (HostVO secondaryStorageHost : secondaryStorageHosts) {
long hostId = secondaryStorageHost.getId();
List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId);
for (VMTemplateHostVO templateHostVO : templateHostVOs) {
if (templateHostVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
String errorMsg = "Please specify a template that is not currently being downloaded.";
s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + secondaryStorageHost.getName() + "; cant' delete it.");
throw new CloudRuntimeException(errorMsg);
}
}
}
Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId()); for (DataStore imageStore : imageStores) {
String eventType = ""; s_logger.info("Delete template from image store: " + imageStore.getName());
AsyncCallFuture<CommandResult> future = this.imageService
.deleteTemplateAsync(this.imageFactory.getTemplate(template.getId(), imageStore));
try {
CommandResult result = future.get();
success = result.isSuccess();
if ( !success )
break;
} catch (InterruptedException e) {
s_logger.debug("delete template Failed", e);
throw new CloudRuntimeException("delete template Failed", e);
} catch (ExecutionException e) {
s_logger.debug("delete template Failed", e);
throw new CloudRuntimeException("delete template Failed", e);
}
}
if (template.getFormat().equals(ImageFormat.ISO)){ if (success) {
eventType = EventTypes.EVENT_ISO_DELETE; s_logger.info("Delete template from template table");
} else { // remove template from vm_templates table
eventType = EventTypes.EVENT_TEMPLATE_DELETE; if (_tmpltDao.remove(template.getId())) {
} // Decrement the number of templates and total secondary storage
// space used by the account
Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId());
_resourceLimitMgr.decrementResourceCount(template.getAccountId(), ResourceType.template);
_resourceLimitMgr.recalculateResourceCount(template.getAccountId(), account.getDomainId(),
ResourceType.secondary_storage.getOrdinal());
}
}
return success;
// Iterate through all necessary secondary storage hosts and mark the template on each host as destroyed
for (HostVO secondaryStorageHost : secondaryStorageHosts) {
long hostId = secondaryStorageHost.getId();
long sZoneId = secondaryStorageHost.getDataCenterId();
List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId);
for (VMTemplateHostVO templateHostVO : templateHostVOs) {
VMTemplateHostVO lock = _tmpltHostDao.acquireInLockTable(templateHostVO.getId());
try {
if (lock == null) {
s_logger.debug("Failed to acquire lock when deleting templateHostVO with ID: " + templateHostVO.getId());
success = false;
break;
}
UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null);
templateHostVO.setDestroyed(true);
_tmpltHostDao.update(templateHostVO.getId(), templateHostVO);
String installPath = templateHostVO.getInstallPath();
List<UserVmVO> userVmUsingIso = _userVmDao.listByIsoId(templateId);
//check if there is any VM using this ISO.
if (userVmUsingIso == null || userVmUsingIso.isEmpty()) {
if (installPath != null) {
Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath));
if (answer == null || !answer.getResult()) {
s_logger.debug("Failed to delete " + templateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails()));
} else {
_tmpltHostDao.remove(templateHostVO.getId());
s_logger.debug("Deleted template at: " + installPath);
}
} else {
_tmpltHostDao.remove(templateHostVO.getId());
}
}
VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(sZoneId, templateId);
if (templateZone != null) {
_tmpltZoneDao.remove(templateZone.getId());
}
} finally {
if (lock != null) {
_tmpltHostDao.releaseFromLockTable(lock.getId());
}
}
}
if (!success) {
break;
}
}
s_logger.debug("Successfully marked template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName);
// If there are no more non-destroyed template host entries for this template, delete it
if (success && (_tmpltHostDao.listByTemplateId(templateId).size() == 0)) {
long accountId = template.getAccountId();
VMTemplateVO lock = _tmpltDao.acquireInLockTable(templateId);
try {
if (lock == null) {
s_logger.debug("Failed to acquire lock when deleting template with ID: " + templateId);
success = false;
} else if (_tmpltDao.remove(templateId)) {
// Decrement the number of templates and total secondary storage space used by the account
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template);
_resourceLimitMgr.recalculateResourceCount(accountId, account.getDomainId(),
ResourceType.secondary_storage.getOrdinal());
}
} finally {
if (lock != null) {
_tmpltDao.releaseFromLockTable(lock.getId());
}
}
s_logger.debug("Removed template: " + template.getName() + " because all of its template host refs were marked as destroyed.");
}
return success;
} }
public TemplateProfile prepareDelete(DeleteTemplateCmd cmd) { public TemplateProfile prepareDelete(DeleteTemplateCmd cmd) {

View File

@ -28,6 +28,7 @@ import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiDBUtils;
@ -75,6 +76,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
protected @Inject DataCenterDao _dcDao; protected @Inject DataCenterDao _dcDao;
protected @Inject VMTemplateDao _tmpltDao; protected @Inject VMTemplateDao _tmpltDao;
protected @Inject VMTemplateHostDao _tmpltHostDao; protected @Inject VMTemplateHostDao _tmpltHostDao;
protected @Inject TemplateDataStoreDao _tmpltStoreDao;
protected @Inject VMTemplateZoneDao _tmpltZoneDao; protected @Inject VMTemplateZoneDao _tmpltZoneDao;
protected @Inject UsageEventDao _usageEventDao; protected @Inject UsageEventDao _usageEventDao;
protected @Inject HostDao _hostDao; protected @Inject HostDao _hostDao;

View File

@ -20,6 +20,7 @@ import java.util.List;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVO;
import com.cloud.exception.InternalErrorException; import com.cloud.exception.InternalErrorException;
@ -39,7 +40,7 @@ public interface TemplateManager extends TemplateApiService{
/** /**
* Prepares a template for vm creation for a certain storage pool. * Prepares a template for vm creation for a certain storage pool.
* *
* @param template * @param template
* template to prepare * template to prepare
* @param pool * @param pool
@ -52,7 +53,7 @@ public interface TemplateManager extends TemplateApiService{
/** /**
* Copies a template from its current secondary storage server to the secondary storage server in the specified zone. * Copies a template from its current secondary storage server to the secondary storage server in the specified zone.
* *
* @param template * @param template
* @param srcSecHost * @param srcSecHost
* @param srcZone * @param srcZone
@ -66,7 +67,7 @@ public interface TemplateManager extends TemplateApiService{
/** /**
* Deletes a template from secondary storage servers * Deletes a template from secondary storage servers
* *
* @param userId * @param userId
* @param templateId * @param templateId
* @param zoneId * @param zoneId
@ -77,7 +78,7 @@ public interface TemplateManager extends TemplateApiService{
/** /**
* Lists templates in the specified storage pool that are not being used by any VM. * Lists templates in the specified storage pool that are not being used by any VM.
* *
* @param pool * @param pool
* @return list of VMTemplateStoragePoolVO * @return list of VMTemplateStoragePoolVO
*/ */
@ -85,13 +86,15 @@ public interface TemplateManager extends TemplateApiService{
/** /**
* Deletes a template in the specified storage pool. * Deletes a template in the specified storage pool.
* *
* @param templatePoolVO * @param templatePoolVO
*/ */
void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO); void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO);
boolean templateIsDeleteable(VMTemplateHostVO templateHostRef); boolean templateIsDeleteable(VMTemplateHostVO templateHostRef);
boolean templateIsDeleteable(TemplateDataStoreVO templateStoreRef);
VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool); VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool);
@ -117,4 +120,6 @@ public interface TemplateManager extends TemplateApiService{
String getChecksum(Long hostId, String templatePath); String getChecksum(Long hostId, String templatePath);
List<DataStore> getImageStoreByTemplate(long templateId, Long zoneId);
} }

View File

@ -65,8 +65,12 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -192,6 +196,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
private final static Logger s_logger = Logger.getLogger(TemplateManagerImpl.class); private final static Logger s_logger = Logger.getLogger(TemplateManagerImpl.class);
@Inject VMTemplateDao _tmpltDao; @Inject VMTemplateDao _tmpltDao;
@Inject VMTemplateHostDao _tmpltHostDao; @Inject VMTemplateHostDao _tmpltHostDao;
@Inject TemplateDataStoreDao _tmplStoreDao;
@Inject VMTemplatePoolDao _tmpltPoolDao; @Inject VMTemplatePoolDao _tmpltPoolDao;
@Inject VMTemplateZoneDao _tmpltZoneDao; @Inject VMTemplateZoneDao _tmpltZoneDao;
@Inject @Inject
@ -253,21 +258,22 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
protected ResourceManager _resourceMgr; protected ResourceManager _resourceMgr;
@Inject VolumeManager volumeMgr; @Inject VolumeManager volumeMgr;
@Inject VMTemplateHostDao templateHostDao; @Inject VMTemplateHostDao templateHostDao;
@Inject ImageStoreDao _imageStoreDao;
int _primaryStorageDownloadWait; int _primaryStorageDownloadWait;
protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch; protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch;
int _storagePoolMaxWaitSeconds = 3600; int _storagePoolMaxWaitSeconds = 3600;
boolean _disableExtraction = false; boolean _disableExtraction = false;
ExecutorService _preloadExecutor; ExecutorService _preloadExecutor;
ScheduledExecutorService _swiftTemplateSyncExecutor; ScheduledExecutorService _swiftTemplateSyncExecutor;
private ScheduledExecutorService _s3TemplateSyncExecutor = null; private ScheduledExecutorService _s3TemplateSyncExecutor = null;
@Inject @Inject
protected List<TemplateAdapter> _adapters; protected List<TemplateAdapter> _adapters;
private TemplateAdapter getAdapter(HypervisorType type) { private TemplateAdapter getAdapter(HypervisorType type) {
TemplateAdapter adapter = null; TemplateAdapter adapter = null;
if (type == HypervisorType.BareMetal) { if (type == HypervisorType.BareMetal) {
@ -276,21 +282,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
// see HyervisorTemplateAdapter // see HyervisorTemplateAdapter
adapter = AdapterBase.getAdapterByName(_adapters, TemplateAdapterType.Hypervisor.getName()); adapter = AdapterBase.getAdapterByName(_adapters, TemplateAdapterType.Hypervisor.getName());
} }
if (adapter == null) { if (adapter == null) {
throw new CloudRuntimeException("Cannot find template adapter for " + type.toString()); throw new CloudRuntimeException("Cannot find template adapter for " + type.toString());
} }
return adapter; return adapter;
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "creating iso") @ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "creating iso")
public VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws ResourceAllocationException{ public VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws ResourceAllocationException{
TemplateAdapter adapter = getAdapter(HypervisorType.None); TemplateAdapter adapter = getAdapter(HypervisorType.None);
TemplateProfile profile = adapter.prepare(cmd); TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile); VMTemplateVO template = adapter.create(profile);
if (template != null){ if (template != null){
return template; return template;
}else { }else {
@ -307,18 +313,18 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied"); throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied");
} }
} }
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor())); TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
TemplateProfile profile = adapter.prepare(cmd); TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile); VMTemplateVO template = adapter.create(profile);
if (template != null){ if (template != null){
return template; return template;
}else { }else {
throw new CloudRuntimeException("Failed to create a template"); throw new CloudRuntimeException("Failed to create a template");
} }
} }
@Override @Override
public DataStore getImageStore(String storeUuid, Long zoneId) { public DataStore getImageStore(String storeUuid, Long zoneId) {
DataStore imageStore = null; DataStore imageStore = null;
@ -331,7 +337,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
imageStore = stores.get(0); imageStore = stores.get(0);
} }
return imageStore; return imageStore;
} }
@ -344,7 +350,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
String url = cmd.getUrl(); String url = cmd.getUrl();
String mode = cmd.getMode(); String mode = cmd.getMode();
Long eventId = cmd.getStartEventId(); Long eventId = cmd.getStartEventId();
// FIXME: async job needs fixing // FIXME: async job needs fixing
Long uploadId = extract(account, templateId, url, zoneId, mode, eventId, true, null, _asyncMgr); Long uploadId = extract(account, templateId, url, zoneId, mode, eventId, true, null, _asyncMgr);
if (uploadId != null){ if (uploadId != null){
@ -372,16 +378,16 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new CloudRuntimeException("Failed to extract the teamplate"); throw new CloudRuntimeException("Failed to extract the teamplate");
} }
} }
@Override @Override
public VirtualMachineTemplate prepareTemplate(long templateId, long zoneId) { public VirtualMachineTemplate prepareTemplate(long templateId, long zoneId) {
VMTemplateVO vmTemplate = _tmpltDao.findById(templateId); VMTemplateVO vmTemplate = _tmpltDao.findById(templateId);
if(vmTemplate == null) if(vmTemplate == null)
throw new InvalidParameterValueException("Unable to find template id=" + templateId); throw new InvalidParameterValueException("Unable to find template id=" + templateId);
_accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.ModifyEntry, true, vmTemplate); _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.ModifyEntry, true, vmTemplate);
prepareTemplateInAllStoragePools(vmTemplate, zoneId); prepareTemplateInAllStoragePools(vmTemplate, zoneId);
return vmTemplate; return vmTemplate;
} }
@ -392,22 +398,22 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
desc = Upload.Type.ISO.toString(); desc = Upload.Type.ISO.toString();
} }
eventId = eventId == null ? 0:eventId; eventId = eventId == null ? 0:eventId;
if (!_accountMgr.isRootAdmin(caller.getType()) && _disableExtraction) { if (!_accountMgr.isRootAdmin(caller.getType()) && _disableExtraction) {
throw new PermissionDeniedException("Extraction has been disabled by admin"); throw new PermissionDeniedException("Extraction has been disabled by admin");
} }
VMTemplateVO template = _tmpltDao.findById(templateId); VMTemplateVO template = _tmpltDao.findById(templateId);
if (template == null || template.getRemoved() != null) { if (template == null || template.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find " +desc+ " with id " + templateId); throw new InvalidParameterValueException("Unable to find " +desc+ " with id " + templateId);
} }
if (template.getTemplateType() == Storage.TemplateType.SYSTEM){ if (template.getTemplateType() == Storage.TemplateType.SYSTEM){
throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " as it is a default System template"); throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " as it is a default System template");
} else if (template.getTemplateType() == Storage.TemplateType.PERHOST){ } else if (template.getTemplateType() == Storage.TemplateType.PERHOST){
throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " as it resides on host and not on SSVM"); throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " as it resides on host and not on SSVM");
} }
if (isISO) { if (isISO) {
if (template.getFormat() != ImageFormat.ISO ){ if (template.getFormat() != ImageFormat.ISO ){
throw new InvalidParameterValueException("Unsupported format, could not extract the ISO"); throw new InvalidParameterValueException("Unsupported format, could not extract the ISO");
@ -417,7 +423,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new InvalidParameterValueException("Unsupported format, could not extract the template"); throw new InvalidParameterValueException("Unsupported format, could not extract the template");
} }
} }
if (zoneId == null && _swiftMgr.isSwiftEnabled()) { if (zoneId == null && _swiftMgr.isSwiftEnabled()) {
zoneId = _swiftMgr.chooseZoneForTmpltExtract(templateId); zoneId = _swiftMgr.chooseZoneForTmpltExtract(templateId);
} }
@ -429,13 +435,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (_dcDao.findById(zoneId) == null) { if (_dcDao.findById(zoneId) == null) {
throw new IllegalArgumentException("Please specify a valid zone."); throw new IllegalArgumentException("Please specify a valid zone.");
} }
if (!_accountMgr.isRootAdmin(caller.getType()) && !template.isExtractable()) { if (!_accountMgr.isRootAdmin(caller.getType()) && !template.isExtractable()) {
throw new InvalidParameterValueException("Unable to extract template id=" + templateId + " as it's not extractable"); throw new InvalidParameterValueException("Unable to extract template id=" + templateId + " as it's not extractable");
} }
_accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template); _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template);
List<HostVO> sservers = getSecondaryStorageHosts(zoneId); List<HostVO> sservers = getSecondaryStorageHosts(zoneId);
VMTemplateHostVO tmpltHostRef = null; VMTemplateHostVO tmpltHostRef = null;
@ -452,7 +458,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
} }
} }
if (tmpltHostRef == null && _swiftMgr.isSwiftEnabled()) { if (tmpltHostRef == null && _swiftMgr.isSwiftEnabled()) {
SwiftTO swift = _swiftMgr.getSwiftTO(templateId); SwiftTO swift = _swiftMgr.getSwiftTO(templateId);
if (swift != null && sservers != null) { if (swift != null && sservers != null) {
@ -468,14 +474,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (tmpltHostRef == null) { if (tmpltHostRef == null) {
throw new InvalidParameterValueException("The " + desc + " has not been downloaded "); throw new InvalidParameterValueException("The " + desc + " has not been downloaded ");
} }
Upload.Mode extractMode; Upload.Mode extractMode;
if (mode == null || (!mode.equalsIgnoreCase(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equalsIgnoreCase(Upload.Mode.HTTP_DOWNLOAD.toString())) ){ if (mode == null || (!mode.equalsIgnoreCase(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equalsIgnoreCase(Upload.Mode.HTTP_DOWNLOAD.toString())) ){
throw new InvalidParameterValueException("Please specify a valid extract Mode. Supported modes: "+ Upload.Mode.FTP_UPLOAD + ", " + Upload.Mode.HTTP_DOWNLOAD); throw new InvalidParameterValueException("Please specify a valid extract Mode. Supported modes: "+ Upload.Mode.FTP_UPLOAD + ", " + Upload.Mode.HTTP_DOWNLOAD);
} else { } else {
extractMode = mode.equalsIgnoreCase(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD; extractMode = mode.equalsIgnoreCase(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD;
} }
if (extractMode == Upload.Mode.FTP_UPLOAD){ if (extractMode == Upload.Mode.FTP_UPLOAD){
URI uri = null; URI uri = null;
try { try {
@ -486,7 +492,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} catch (Exception ex) { } catch (Exception ex) {
throw new InvalidParameterValueException("Invalid url given: " + url); throw new InvalidParameterValueException("Invalid url given: " + url);
} }
String host = uri.getHost(); String host = uri.getHost();
try { try {
InetAddress hostAddr = InetAddress.getByName(host); InetAddress hostAddr = InetAddress.getByName(host);
@ -499,22 +505,22 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
throw new InvalidParameterValueException("Unable to resolve " + host); throw new InvalidParameterValueException("Unable to resolve " + host);
} }
if (_uploadMonitor.isTypeUploadInProgress(templateId, isISO ? Type.ISO : Type.TEMPLATE) ){ if (_uploadMonitor.isTypeUploadInProgress(templateId, isISO ? Type.ISO : Type.TEMPLATE) ){
throw new IllegalArgumentException(template.getName() + " upload is in progress. Please wait for some time to schedule another upload for the same"); throw new IllegalArgumentException(template.getName() + " upload is in progress. Please wait for some time to schedule another upload for the same");
} }
return _uploadMonitor.extractTemplate(template, url, tmpltHostRef, zoneId, eventId, job.getId(), mgr); return _uploadMonitor.extractTemplate(template, url, tmpltHostRef, zoneId, eventId, job.getId(), mgr);
} }
UploadVO vo = _uploadMonitor.createEntityDownloadURL(template, tmpltHostRef, zoneId, eventId); UploadVO vo = _uploadMonitor.createEntityDownloadURL(template, tmpltHostRef, zoneId, eventId);
if (vo != null){ if (vo != null){
return vo.getId(); return vo.getId();
}else{ }else{
return null; return null;
} }
} }
public void prepareTemplateInAllStoragePools(final VMTemplateVO template, long zoneId) { public void prepareTemplateInAllStoragePools(final VMTemplateVO template, long zoneId) {
List<StoragePoolVO> pools = _poolDao.listByStatus(StoragePoolStatus.Up); List<StoragePoolVO> pools = _poolDao.listByStatus(StoragePoolStatus.Up);
for(final StoragePoolVO pool : pools) { for(final StoragePoolVO pool : pools) {
@ -528,7 +534,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
s_logger.warn("Unexpected exception ", e); s_logger.warn("Unexpected exception ", e);
} }
} }
private void reallyRun() { private void reallyRun() {
s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId()); s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId());
StoragePool pol = (StoragePool)dataStoreMgr.getPrimaryDataStore(pool.getId()); StoragePool pol = (StoragePool)dataStoreMgr.getPrimaryDataStore(pool.getId());
@ -541,7 +547,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
} }
} }
String downloadTemplateFromSwiftToSecondaryStorage(long dcId, long templateId){ String downloadTemplateFromSwiftToSecondaryStorage(long dcId, long templateId){
VMTemplateVO template = _tmpltDao.findById(templateId); VMTemplateVO template = _tmpltDao.findById(templateId);
if ( template == null ) { if ( template == null ) {
@ -648,7 +654,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
@Override @DB @Override @DB
public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO templ, StoragePool pool) { public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO templ, StoragePool pool) {
VMTemplateVO template = _tmpltDao.findById(templ.getId(), true); VMTemplateVO template = _tmpltDao.findById(templ.getId(), true);
long poolId = pool.getId(); long poolId = pool.getId();
long templateId = template.getId(); long templateId = template.getId();
long dcId = pool.getDataCenterId(); long dcId = pool.getDataCenterId();
@ -656,23 +662,23 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
VMTemplateHostVO templateHostRef = null; VMTemplateHostVO templateHostRef = null;
long templateStoragePoolRefId; long templateStoragePoolRefId;
String origUrl = null; String origUrl = null;
templateStoragePoolRef = _tmpltPoolDao.findByPoolTemplate(poolId, templateId); templateStoragePoolRef = _tmpltPoolDao.findByPoolTemplate(poolId, templateId);
if (templateStoragePoolRef != null) { if (templateStoragePoolRef != null) {
templateStoragePoolRef.setMarkedForGC(false); templateStoragePoolRef.setMarkedForGC(false);
_tmpltPoolDao.update(templateStoragePoolRef.getId(), templateStoragePoolRef); _tmpltPoolDao.update(templateStoragePoolRef.getId(), templateStoragePoolRef);
if (templateStoragePoolRef.getDownloadState() == Status.DOWNLOADED) { if (templateStoragePoolRef.getDownloadState() == Status.DOWNLOADED) {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Template " + templateId + " has already been downloaded to pool " + poolId); s_logger.debug("Template " + templateId + " has already been downloaded to pool " + poolId);
} }
return templateStoragePoolRef; return templateStoragePoolRef;
} }
} }
templateHostRef = findVmTemplateHost(templateId, pool); templateHostRef = findVmTemplateHost(templateId, pool);
if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) {
String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId); String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId);
if (result != null) { if (result != null) {
@ -691,13 +697,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return null; return null;
} }
} }
HostVO sh = _hostDao.findById(templateHostRef.getHostId()); HostVO sh = _hostDao.findById(templateHostRef.getHostId());
origUrl = sh.getStorageUrl(); origUrl = sh.getStorageUrl();
if (origUrl == null) { if (origUrl == null) {
throw new CloudRuntimeException("Unable to find the orig.url from host " + sh.toString()); throw new CloudRuntimeException("Unable to find the orig.url from host " + sh.toString());
} }
if (templateStoragePoolRef == null) { if (templateStoragePoolRef == null) {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Downloading template " + templateId + " to pool " + poolId); s_logger.debug("Downloading template " + templateId + " to pool " + poolId);
@ -706,7 +712,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
try { try {
templateStoragePoolRef = _tmpltPoolDao.persist(templateStoragePoolRef); templateStoragePoolRef = _tmpltPoolDao.persist(templateStoragePoolRef);
templateStoragePoolRefId = templateStoragePoolRef.getId(); templateStoragePoolRefId = templateStoragePoolRef.getId();
} catch (Exception e) { } catch (Exception e) {
s_logger.debug("Assuming we're in a race condition: " + e.getMessage()); s_logger.debug("Assuming we're in a race condition: " + e.getMessage());
templateStoragePoolRef = _tmpltPoolDao.findByPoolTemplate(poolId, templateId); templateStoragePoolRef = _tmpltPoolDao.findByPoolTemplate(poolId, templateId);
@ -718,12 +724,12 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} else { } else {
templateStoragePoolRefId = templateStoragePoolRef.getId(); templateStoragePoolRefId = templateStoragePoolRef.getId();
} }
List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up); List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up);
if (vos == null || vos.isEmpty()){ if (vos == null || vos.isEmpty()){
throw new CloudRuntimeException("Cannot download " + templateId + " to poolId " + poolId + " since there is no host in the Up state connected to this pool"); throw new CloudRuntimeException("Cannot download " + templateId + " to poolId " + poolId + " since there is no host in the Up state connected to this pool");
} }
templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, _storagePoolMaxWaitSeconds); templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, _storagePoolMaxWaitSeconds);
if (templateStoragePoolRef == null) { if (templateStoragePoolRef == null) {
throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templateStoragePoolRefId); throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templateStoragePoolRefId);
@ -734,13 +740,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return templateStoragePoolRef; return templateStoragePoolRef;
} }
String url = origUrl + "/" + templateHostRef.getInstallPath(); String url = origUrl + "/" + templateHostRef.getInstallPath();
PrimaryStorageDownloadCommand dcmd = new PrimaryStorageDownloadCommand(template.getUniqueName(), url, template.getFormat(), PrimaryStorageDownloadCommand dcmd = new PrimaryStorageDownloadCommand(template.getUniqueName(), url, template.getFormat(),
template.getAccountId(), pool, _primaryStorageDownloadWait); template.getAccountId(), pool, _primaryStorageDownloadWait);
HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId()); HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId());
assert(secondaryStorageHost != null); assert(secondaryStorageHost != null);
dcmd.setSecondaryStorageUrl(secondaryStorageHost.getStorageUrl()); dcmd.setSecondaryStorageUrl(secondaryStorageHost.getStorageUrl());
for (int retry = 0; retry < 2; retry ++){ for (int retry = 0; retry < 2; retry ++){
Collections.shuffle(vos); // Shuffling to pick a random host in the vm deployment retries Collections.shuffle(vos); // Shuffling to pick a random host in the vm deployment retries
StoragePoolHostVO vo = vos.get(0); StoragePoolHostVO vo = vos.get(0);
@ -749,7 +755,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
dcmd.setLocalPath(vo.getLocalPath()); dcmd.setLocalPath(vo.getLocalPath());
// set 120 min timeout for this command // set 120 min timeout for this command
PrimaryStorageDownloadAnswer answer = (PrimaryStorageDownloadAnswer)_agentMgr.easySend( PrimaryStorageDownloadAnswer answer = (PrimaryStorageDownloadAnswer)_agentMgr.easySend(
_hvGuruMgr.getGuruProcessedCommandTargetHost(vo.getHostId(), dcmd), dcmd); _hvGuruMgr.getGuruProcessedCommandTargetHost(vo.getHostId(), dcmd), dcmd);
if (answer != null && answer.getResult() ) { if (answer != null && answer.getResult() ) {
@ -776,10 +782,10 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return null; return null;
} }
@Override @Override
public VMTemplateHostVO findVmTemplateHost(long templateId, public VMTemplateHostVO findVmTemplateHost(long templateId,
StoragePool pool) { StoragePool pool) {
@ -813,7 +819,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return null; return null;
} }
@Override @Override
public String getChecksum(Long hostId, String templatePath) { public String getChecksum(Long hostId, String templatePath) {
HostVO ssHost = _hostDao.findById(hostId); HostVO ssHost = _hostDao.findById(hostId);
@ -831,7 +837,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return null; return null;
} }
@Override @Override
@DB @DB
public VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool) { public VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool) {
@ -873,22 +879,22 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
public boolean resetTemplateDownloadStateOnPool(long templateStoragePoolRefId) { public boolean resetTemplateDownloadStateOnPool(long templateStoragePoolRefId) {
// have to use the same lock that prepareTemplateForCreate use to maintain state consistency // have to use the same lock that prepareTemplateForCreate use to maintain state consistency
VMTemplateStoragePoolVO templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, 1200); VMTemplateStoragePoolVO templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, 1200);
if (templateStoragePoolRef == null) { if (templateStoragePoolRef == null) {
s_logger.warn("resetTemplateDownloadStateOnPool failed - unable to lock TemplateStorgePoolRef " + templateStoragePoolRefId); s_logger.warn("resetTemplateDownloadStateOnPool failed - unable to lock TemplateStorgePoolRef " + templateStoragePoolRefId);
return false; return false;
} }
try { try {
templateStoragePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED); templateStoragePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED);
_tmpltPoolDao.update(templateStoragePoolRefId, templateStoragePoolRef); _tmpltPoolDao.update(templateStoragePoolRefId, templateStoragePoolRef);
} finally { } finally {
_tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId); _tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId);
} }
return true; return true;
} }
@Override @Override
@DB @DB
public boolean copy(long userId, VMTemplateVO template, HostVO srcSecHost, DataCenterVO srcZone, DataCenterVO dstZone) throws StorageUnavailableException, ResourceAllocationException { public boolean copy(long userId, VMTemplateVO template, HostVO srcSecHost, DataCenterVO srcZone, DataCenterVO dstZone) throws StorageUnavailableException, ResourceAllocationException {
@ -930,7 +936,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} else { } else {
dstTmpltHost.setDestroyed(false); dstTmpltHost.setDestroyed(false);
_tmpltHostDao.update(dstTmpltHost.getId(), dstTmpltHost); _tmpltHostDao.update(dstTmpltHost.getId(), dstTmpltHost);
return true; return true;
} }
} else if (dstTmpltHost != null && dstTmpltHost.getDownloadState() == Status.DOWNLOAD_ERROR){ } else if (dstTmpltHost != null && dstTmpltHost.getDownloadState() == Status.DOWNLOAD_ERROR){
@ -951,7 +957,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if(_downloadMonitor.copyTemplate(template, srcSecHost, dstSecHost) ) { if(_downloadMonitor.copyTemplate(template, srcSecHost, dstSecHost) ) {
_tmpltDao.addTemplateToZone(template, dstZoneId); _tmpltDao.addTemplateToZone(template, dstZoneId);
if(account.getId() != Account.ACCOUNT_ID_SYSTEM){ if(account.getId() != Account.ACCOUNT_ID_SYSTEM){
UsageEventUtils.publishUsageEvent(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltHost.getSize(), UsageEventUtils.publishUsageEvent(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltHost.getSize(),
template.getClass().getName(), template.getUuid()); template.getClass().getName(), template.getUuid());
@ -961,8 +967,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return false; return false;
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_COPY, eventDescription = "copying template", async = true) @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_COPY, eventDescription = "copying template", async = true)
public VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException { public VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException {
@ -971,7 +977,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
Long sourceZoneId = cmd.getSourceZoneId(); Long sourceZoneId = cmd.getSourceZoneId();
Long destZoneId = cmd.getDestinationZoneId(); Long destZoneId = cmd.getDestinationZoneId();
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
if (_swiftMgr.isSwiftEnabled()) { if (_swiftMgr.isSwiftEnabled()) {
throw new CloudRuntimeException("copytemplate API is disabled in Swift setup, templates in Swift can be accessed by all Zones"); throw new CloudRuntimeException("copytemplate API is disabled in Swift setup, templates in Swift can be accessed by all Zones");
} }
@ -985,37 +991,37 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (sourceZoneId == destZoneId) { if (sourceZoneId == destZoneId) {
throw new InvalidParameterValueException("Please specify different source and destination zones."); throw new InvalidParameterValueException("Please specify different source and destination zones.");
} }
DataCenterVO sourceZone = _dcDao.findById(sourceZoneId); DataCenterVO sourceZone = _dcDao.findById(sourceZoneId);
if (sourceZone == null) { if (sourceZone == null) {
throw new InvalidParameterValueException("Please specify a valid source zone."); throw new InvalidParameterValueException("Please specify a valid source zone.");
} }
DataCenterVO dstZone = _dcDao.findById(destZoneId); DataCenterVO dstZone = _dcDao.findById(destZoneId);
if (dstZone == null) { if (dstZone == null) {
throw new InvalidParameterValueException("Please specify a valid destination zone."); throw new InvalidParameterValueException("Please specify a valid destination zone.");
} }
VMTemplateVO template = _tmpltDao.findById(templateId); VMTemplateVO template = _tmpltDao.findById(templateId);
if (template == null || template.getRemoved() != null) { if (template == null || template.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find template with id"); throw new InvalidParameterValueException("Unable to find template with id");
} }
HostVO dstSecHost = getSecondaryStorageHost(destZoneId, templateId); HostVO dstSecHost = getSecondaryStorageHost(destZoneId, templateId);
if ( dstSecHost != null ) { if ( dstSecHost != null ) {
s_logger.debug("There is template " + templateId + " in secondary storage " + dstSecHost.getId() + " in zone " + destZoneId + " , don't need to copy"); s_logger.debug("There is template " + templateId + " in secondary storage " + dstSecHost.getId() + " in zone " + destZoneId + " , don't need to copy");
return template; return template;
} }
HostVO srcSecHost = getSecondaryStorageHost(sourceZoneId, templateId); HostVO srcSecHost = getSecondaryStorageHost(sourceZoneId, templateId);
if ( srcSecHost == null ) { if ( srcSecHost == null ) {
throw new InvalidParameterValueException("There is no template " + templateId + " in zone " + sourceZoneId ); throw new InvalidParameterValueException("There is no template " + templateId + " in zone " + sourceZoneId );
} }
_accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template); _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template);
boolean success = copy(userId, template, srcSecHost, sourceZone, dstZone); boolean success = copy(userId, template, srcSecHost, sourceZone, dstZone);
if (success){ if (success){
return template; return template;
}else { }else {
@ -1029,24 +1035,24 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (template == null || template.getRemoved() != null) { if (template == null || template.getRemoved() != null) {
throw new InvalidParameterValueException("Please specify a valid template."); throw new InvalidParameterValueException("Please specify a valid template.");
} }
TemplateAdapter adapter = getAdapter(template.getHypervisorType()); TemplateAdapter adapter = getAdapter(template.getHypervisorType());
return adapter.delete(new TemplateProfile(userId, template, zoneId)); return adapter.delete(new TemplateProfile(userId, template, zoneId));
} }
@Override @Override
public List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool) { public List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool) {
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = new ArrayList<VMTemplateStoragePoolVO>(); List<VMTemplateStoragePoolVO> unusedTemplatesInPool = new ArrayList<VMTemplateStoragePoolVO>();
List<VMTemplateStoragePoolVO> allTemplatesInPool = _tmpltPoolDao.listByPoolId(pool.getId()); List<VMTemplateStoragePoolVO> allTemplatesInPool = _tmpltPoolDao.listByPoolId(pool.getId());
for (VMTemplateStoragePoolVO templatePoolVO : allTemplatesInPool) { for (VMTemplateStoragePoolVO templatePoolVO : allTemplatesInPool) {
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId()); VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
// If this is a routing template, consider it in use // If this is a routing template, consider it in use
if (template.getTemplateType() == TemplateType.SYSTEM) { if (template.getTemplateType() == TemplateType.SYSTEM) {
continue; continue;
} }
// If the template is not yet downloaded to the pool, consider it in use // If the template is not yet downloaded to the pool, consider it in use
if (templatePoolVO.getDownloadState() != Status.DOWNLOADED) { if (templatePoolVO.getDownloadState() != Status.DOWNLOADED) {
continue; continue;
@ -1056,24 +1062,24 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
unusedTemplatesInPool.add(templatePoolVO); unusedTemplatesInPool.add(templatePoolVO);
} }
} }
return unusedTemplatesInPool; return unusedTemplatesInPool;
} }
@Override @Override
public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) { public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) {
StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId());
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId()); VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Evicting " + templatePoolVO); s_logger.debug("Evicting " + templatePoolVO);
} }
DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO); DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO);
try { try {
Answer answer = _storageMgr.sendToPool(pool, cmd); Answer answer = _storageMgr.sendToPool(pool, cmd);
if (answer != null && answer.getResult()) { if (answer != null && answer.getResult()) {
// Remove the templatePoolVO // Remove the templatePoolVO
if (_tmpltPoolDao.remove(templatePoolVO.getId())) { if (_tmpltPoolDao.remove(templatePoolVO.getId())) {
@ -1087,7 +1093,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
} }
void swiftTemplateSync() { void swiftTemplateSync() {
GlobalLock swiftTemplateSyncLock = GlobalLock.getInternLock("templatemgr.swiftTemplateSync"); GlobalLock swiftTemplateSyncLock = GlobalLock.getInternLock("templatemgr.swiftTemplateSync");
try { try {
@ -1187,7 +1193,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
@Override @Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
final Map<String, String> configs = _configDao.getConfiguration("AgentManager", params); final Map<String, String> configs = _configDao.getConfiguration("AgentManager", params);
_routerTemplateId = NumbersUtil.parseInt(configs.get("router.template.id"), 1); _routerTemplateId = NumbersUtil.parseInt(configs.get("router.template.id"), 1);
@ -1200,14 +1206,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
HostTemplateStatesSearch = _tmpltHostDao.createSearchBuilder(); HostTemplateStatesSearch = _tmpltHostDao.createSearchBuilder();
HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ); HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ);
SearchBuilder<HostVO> HostSearch = _hostDao.createSearchBuilder(); SearchBuilder<HostVO> HostSearch = _hostDao.createSearchBuilder();
HostSearch.and("dcId", HostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); HostSearch.and("dcId", HostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
HostTemplateStatesSearch.join("host", HostSearch, HostSearch.entity().getId(), HostTemplateStatesSearch.entity().getHostId(), JoinBuilder.JoinType.INNER); HostTemplateStatesSearch.join("host", HostSearch, HostSearch.entity().getId(), HostTemplateStatesSearch.entity().getHostId(), JoinBuilder.JoinType.INNER);
HostSearch.done(); HostSearch.done();
HostTemplateStatesSearch.done(); HostTemplateStatesSearch.done();
_storagePoolMaxWaitSeconds = NumbersUtil.parseInt(_configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600); _storagePoolMaxWaitSeconds = NumbersUtil.parseInt(_configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
_preloadExecutor = Executors.newFixedThreadPool(8, new NamedThreadFactory("Template-Preloader")); _preloadExecutor = Executors.newFixedThreadPool(8, new NamedThreadFactory("Template-Preloader"));
_swiftTemplateSyncExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("swift-template-sync-Executor")); _swiftTemplateSyncExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("swift-template-sync-Executor"));
@ -1222,7 +1228,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return true; return true;
} }
protected TemplateManagerImpl() { protected TemplateManagerImpl() {
} }
@ -1260,23 +1266,57 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return true; return true;
} }
@Override
public boolean templateIsDeleteable(TemplateDataStoreVO templateStoreRef) {
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templateStoreRef.getTemplateId());
long templateId = template.getId();
ImageStoreVO imageStore = _imageStoreDao.findById(templateStoreRef.getDataStoreId());
long zoneId = imageStore.getDataCenterId();
DataCenterVO zone = _dcDao.findById(zoneId);
// Check if there are VMs running in the template host ref's zone that use the template
List<VMInstanceVO> nonExpungedVms = _vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateId);
if (!nonExpungedVms.isEmpty()) {
s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are non-expunged VMs deployed from this template.");
return false;
}
List<UserVmVO> userVmUsingIso = _userVmDao.listByIsoId(templateId);
//check if there is any VM using this ISO.
if (!userVmUsingIso.isEmpty()) {
s_logger.debug("ISO " + template.getName() + " in zone " + zone.getName() + " is not deleteable because it is attached to " + userVmUsingIso.size() + " VMs");
return false;
}
// Check if there are any snapshots for the template in the template host ref's zone
List<VolumeVO> volumes = _volumeDao.findByTemplateAndZone(templateId, zoneId);
for (VolumeVO volume : volumes) {
List<SnapshotVO> snapshots = _snapshotDao.listByVolumeIdVersion(volume.getId(), "2.1");
if (!snapshots.isEmpty()) {
s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are 2.1 snapshots using this template.");
return false;
}
}
return true;
}
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_DETACH, eventDescription = "detaching ISO", async = true) @ActionEvent(eventType = EventTypes.EVENT_ISO_DETACH, eventDescription = "detaching ISO", async = true)
public boolean detachIso(long vmId) { public boolean detachIso(long vmId) {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
Long userId = UserContext.current().getCallerUserId(); Long userId = UserContext.current().getCallerUserId();
// Verify input parameters // Verify input parameters
UserVmVO vmInstanceCheck = _userVmDao.findById(vmId); UserVmVO vmInstanceCheck = _userVmDao.findById(vmId);
if (vmInstanceCheck == null) { if (vmInstanceCheck == null) {
throw new InvalidParameterValueException ("Unable to find a virtual machine with id " + vmId); throw new InvalidParameterValueException ("Unable to find a virtual machine with id " + vmId);
} }
UserVm userVM = _userVmDao.findById(vmId); UserVm userVM = _userVmDao.findById(vmId);
if (userVM == null) { if (userVM == null) {
throw new InvalidParameterValueException("Please specify a valid VM."); throw new InvalidParameterValueException("Please specify a valid VM.");
} }
_accountMgr.checkAccess(caller, null, true, userVM); _accountMgr.checkAccess(caller, null, true, userVM);
Long isoId = userVM.getIsoId(); Long isoId = userVM.getIsoId();
@ -1284,7 +1324,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new InvalidParameterValueException("The specified VM has no ISO attached to it."); throw new InvalidParameterValueException("The specified VM has no ISO attached to it.");
} }
UserContext.current().setEventDetails("Vm Id: " +vmId+ " ISO Id: "+isoId); UserContext.current().setEventDetails("Vm Id: " +vmId+ " ISO Id: "+isoId);
State vmState = userVM.getState(); State vmState = userVM.getState();
if (vmState != State.Running && vmState != State.Stopped) { if (vmState != State.Running && vmState != State.Stopped) {
throw new InvalidParameterValueException("Please specify a VM that is either Stopped or Running."); throw new InvalidParameterValueException("Please specify a VM that is either Stopped or Running.");
@ -1295,44 +1335,44 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return result; return result;
}else { }else {
throw new CloudRuntimeException("Failed to detach iso"); throw new CloudRuntimeException("Failed to detach iso");
} }
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_ATTACH, eventDescription = "attaching ISO", async = true) @ActionEvent(eventType = EventTypes.EVENT_ISO_ATTACH, eventDescription = "attaching ISO", async = true)
public boolean attachIso(long isoId, long vmId) { public boolean attachIso(long isoId, long vmId) {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
Long userId = UserContext.current().getCallerUserId(); Long userId = UserContext.current().getCallerUserId();
// Verify input parameters // Verify input parameters
UserVmVO vm = _userVmDao.findById(vmId); UserVmVO vm = _userVmDao.findById(vmId);
if (vm == null) { if (vm == null) {
throw new InvalidParameterValueException("Unable to find a virtual machine with id " + vmId); throw new InvalidParameterValueException("Unable to find a virtual machine with id " + vmId);
} }
VMTemplateVO iso = _tmpltDao.findById(isoId); VMTemplateVO iso = _tmpltDao.findById(isoId);
if (iso == null || iso.getRemoved() != null) { if (iso == null || iso.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find an ISO with id " + isoId); throw new InvalidParameterValueException("Unable to find an ISO with id " + isoId);
} }
//check permissions //check permissions
//check if caller has access to VM and ISO //check if caller has access to VM and ISO
//and also check if the VM's owner has access to the ISO. //and also check if the VM's owner has access to the ISO.
_accountMgr.checkAccess(caller, null, false, iso, vm); _accountMgr.checkAccess(caller, null, false, iso, vm);
Account vmOwner = _accountDao.findById(vm.getAccountId()); Account vmOwner = _accountDao.findById(vm.getAccountId());
_accountMgr.checkAccess(vmOwner, null, false, iso, vm); _accountMgr.checkAccess(vmOwner, null, false, iso, vm);
State vmState = vm.getState(); State vmState = vm.getState();
if (vmState != State.Running && vmState != State.Stopped) { if (vmState != State.Running && vmState != State.Stopped) {
throw new InvalidParameterValueException("Please specify a VM that is either Stopped or Running."); throw new InvalidParameterValueException("Please specify a VM that is either Stopped or Running.");
} }
if ("xen-pv-drv-iso".equals(iso.getDisplayText()) && vm.getHypervisorType() != Hypervisor.HypervisorType.XenServer){ if ("xen-pv-drv-iso".equals(iso.getDisplayText()) && vm.getHypervisorType() != Hypervisor.HypervisorType.XenServer){
throw new InvalidParameterValueException("Cannot attach Xenserver PV drivers to incompatible hypervisor " + vm.getHypervisorType()); throw new InvalidParameterValueException("Cannot attach Xenserver PV drivers to incompatible hypervisor " + vm.getHypervisorType());
} }
if("vmware-tools.iso".equals(iso.getName()) && vm.getHypervisorType() != Hypervisor.HypervisorType.VMware) { if("vmware-tools.iso".equals(iso.getName()) && vm.getHypervisorType() != Hypervisor.HypervisorType.VMware) {
throw new InvalidParameterValueException("Cannot attach VMware tools drivers to incompatible hypervisor " + vm.getHypervisorType()); throw new InvalidParameterValueException("Cannot attach VMware tools drivers to incompatible hypervisor " + vm.getHypervisorType());
} }
@ -1343,7 +1383,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new CloudRuntimeException("Failed to attach iso"); throw new CloudRuntimeException("Failed to attach iso");
} }
} }
private boolean attachISOToVM(long vmId, long isoId, boolean attach) { private boolean attachISOToVM(long vmId, long isoId, boolean attach) {
UserVmVO vm = this._userVmDao.findById(vmId); UserVmVO vm = this._userVmDao.findById(vmId);
@ -1397,41 +1437,43 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if ( success && attach) { if ( success && attach) {
vm.setIsoId(iso.getId()); vm.setIsoId(iso.getId());
_userVmDao.update(vmId, vm); _userVmDao.update(vmId, vm);
} }
if ( success && !attach ) { if ( success && !attach ) {
vm.setIsoId(null); vm.setIsoId(null);
_userVmDao.update(vmId, vm); _userVmDao.update(vmId, vm);
} }
return success; return success;
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_DELETE, eventDescription = "deleting template", async = true) @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_DELETE, eventDescription = "deleting template", async = true)
public boolean deleteTemplate(DeleteTemplateCmd cmd) { public boolean deleteTemplate(DeleteTemplateCmd cmd) {
Long templateId = cmd.getId(); Long templateId = cmd.getId();
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
VirtualMachineTemplate template = getTemplate(templateId); VirtualMachineTemplate template = getTemplate(templateId);
if (template == null) { if (template == null) {
throw new InvalidParameterValueException("unable to find template with id " + templateId); throw new InvalidParameterValueException("unable to find template with id " + templateId);
} }
_accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template); _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template);
if (template.getFormat() == ImageFormat.ISO) { if (template.getFormat() == ImageFormat.ISO) {
throw new InvalidParameterValueException("Please specify a valid template."); throw new InvalidParameterValueException("Please specify a valid template.");
} }
/*
if (cmd.getZoneId() == null && _swiftMgr.isSwiftEnabled()) { if (cmd.getZoneId() == null && _swiftMgr.isSwiftEnabled()) {
_swiftMgr.deleteTemplate(cmd); _swiftMgr.deleteTemplate(cmd);
} }
if (cmd.getZoneId() == null && _s3Mgr.isS3Enabled()) { if (cmd.getZoneId() == null && _s3Mgr.isS3Enabled()) {
_s3Mgr.deleteTemplate(cmd.getId(), caller.getAccountId()); _s3Mgr.deleteTemplate(cmd.getId(), caller.getAccountId());
} }
*/
TemplateAdapter adapter = getAdapter(template.getHypervisorType()); TemplateAdapter adapter = getAdapter(template.getHypervisorType());
TemplateProfile profile = adapter.prepareDelete(cmd); TemplateProfile profile = adapter.prepareDelete(cmd);
boolean result = adapter.delete(profile); boolean result = adapter.delete(profile);
if (result){ if (result){
if (cmd.getZoneId() == null if (cmd.getZoneId() == null
&& (_swiftMgr.isSwiftEnabled() || _s3Mgr.isS3Enabled())) { && (_swiftMgr.isSwiftEnabled() || _s3Mgr.isS3Enabled())) {
@ -1448,21 +1490,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new CloudRuntimeException("Failed to delete template"); throw new CloudRuntimeException("Failed to delete template");
} }
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_DELETE, eventDescription = "deleting iso", async = true) @ActionEvent(eventType = EventTypes.EVENT_ISO_DELETE, eventDescription = "deleting iso", async = true)
public boolean deleteIso(DeleteIsoCmd cmd) { public boolean deleteIso(DeleteIsoCmd cmd) {
Long templateId = cmd.getId(); Long templateId = cmd.getId();
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
Long zoneId = cmd.getZoneId(); Long zoneId = cmd.getZoneId();
VirtualMachineTemplate template = getTemplate(templateId);; VirtualMachineTemplate template = getTemplate(templateId);;
if (template == null) { if (template == null) {
throw new InvalidParameterValueException("unable to find iso with id " + templateId); throw new InvalidParameterValueException("unable to find iso with id " + templateId);
} }
_accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template); _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template);
if (template.getFormat() != ImageFormat.ISO) { if (template.getFormat() != ImageFormat.ISO) {
throw new InvalidParameterValueException("Please specify a valid iso."); throw new InvalidParameterValueException("Please specify a valid iso.");
} }
@ -1495,17 +1537,17 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new CloudRuntimeException("Failed to delete ISO"); throw new CloudRuntimeException("Failed to delete ISO");
} }
} }
@Override @Override
public VirtualMachineTemplate getTemplate(long templateId) { public VirtualMachineTemplate getTemplate(long templateId) {
VMTemplateVO template = _tmpltDao.findById(templateId); VMTemplateVO template = _tmpltDao.findById(templateId);
if (template != null && template.getRemoved() == null) { if (template != null && template.getRemoved() == null) {
return template; return template;
} }
return null; return null;
} }
@Override @Override
public List<String> listTemplatePermissions(BaseListTemplateOrIsoPermissionsCmd cmd) { public List<String> listTemplatePermissions(BaseListTemplateOrIsoPermissionsCmd cmd) {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
@ -1519,7 +1561,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (template == null) { if (template == null) {
throw new InvalidParameterValueException("unable to find " + cmd.getMediaType() + " with id " + id); throw new InvalidParameterValueException("unable to find " + cmd.getMediaType() + " with id " + id);
} }
if (cmd instanceof ListTemplatePermissionsCmd) { if (cmd instanceof ListTemplatePermissionsCmd) {
if (template.getFormat().equals(ImageFormat.ISO)) { if (template.getFormat().equals(ImageFormat.ISO)) {
throw new InvalidParameterValueException("Please provide a valid template"); throw new InvalidParameterValueException("Please provide a valid template");
@ -1544,7 +1586,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return accountNames; return accountNames;
} }
@DB @DB
@Override @Override
public boolean updateTemplateOrIsoPermissions(BaseUpdateTemplateOrIsoPermissionsCmd cmd) { public boolean updateTemplateOrIsoPermissions(BaseUpdateTemplateOrIsoPermissionsCmd cmd) {
@ -1579,7 +1621,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new InvalidParameterValueException("Please provide a valid iso"); throw new InvalidParameterValueException("Please provide a valid iso");
} }
} }
//convert projectIds to accountNames //convert projectIds to accountNames
if (projectIds != null) { if (projectIds != null) {
for (Long projectId : projectIds) { for (Long projectId : projectIds) {
@ -1587,7 +1629,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (project == null) { if (project == null) {
throw new InvalidParameterValueException("Unable to find project by id " + projectId); throw new InvalidParameterValueException("Unable to find project by id " + projectId);
} }
if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) { if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) {
throw new InvalidParameterValueException("Account " + caller + " can't access project id=" + projectId); throw new InvalidParameterValueException("Account " + caller + " can't access project id=" + projectId);
} }
@ -1636,7 +1678,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (isFeatured != null) { if (isFeatured != null) {
updatedTemplate.setFeatured(isFeatured.booleanValue()); updatedTemplate.setFeatured(isFeatured.booleanValue());
} }
if (isExtractable != null && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) {//Only ROOT admins allowed to change this powerful attribute if (isExtractable != null && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) {//Only ROOT admins allowed to change this powerful attribute
updatedTemplate.setExtractable(isExtractable.booleanValue()); updatedTemplate.setExtractable(isExtractable.booleanValue());
}else if (isExtractable != null && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { }else if (isExtractable != null && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
@ -1686,15 +1728,15 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return true; return true;
} }
private String getRandomPrivateTemplateName() { private String getRandomPrivateTemplateName() {
return UUID.randomUUID().toString(); return UUID.randomUUID().toString();
} }
@Override @Override
@DB @DB
@ -1733,7 +1775,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new CloudRuntimeException( throw new CloudRuntimeException(
"Creating private Template need to specify snapshotId or volumeId"); "Creating private Template need to specify snapshotId or volumeId");
} }
CommandResult result = null; CommandResult result = null;
try { try {
result = future.get(); result = future.get();
@ -1742,7 +1784,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
s_logger.debug("Failed to create template" + result.getResult()); s_logger.debug("Failed to create template" + result.getResult());
throw new CloudRuntimeException("Failed to create template" + result.getResult()); throw new CloudRuntimeException("Failed to create template" + result.getResult());
} }
privateTemplate = this._tmpltDao.findById(templateId); privateTemplate = this._tmpltDao.findById(templateId);
UsageEventVO usageEvent = new UsageEventVO( UsageEventVO usageEvent = new UsageEventVO(
EventTypes.EVENT_TEMPLATE_CREATE, EventTypes.EVENT_TEMPLATE_CREATE,
@ -1990,7 +2032,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
} }
@Override @Override
public Pair<String, String> getAbsoluteIsoPath(long templateId, public Pair<String, String> getAbsoluteIsoPath(long templateId,
long dataCenterId) { long dataCenterId) {
@ -2108,7 +2150,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} }
return hosts; return hosts;
} }
@Override @Override
public Long getTemplateSize(long templateId, long zoneId) { public Long getTemplateSize(long templateId, long zoneId) {
SearchCriteria<VMTemplateHostVO> sc = HostTemplateStatesSearch.create(); SearchCriteria<VMTemplateHostVO> sc = HostTemplateStatesSearch.create();
@ -2145,4 +2187,24 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return size; return size;
} }
// find image store where this template is located
@Override
public List<DataStore> getImageStoreByTemplate(long templateId, Long zoneId) {
// find all eligible image stores for this zone scope
List<DataStore> imageStores = this.dataStoreMgr.getImageStoresByScope(new ZoneScope(zoneId));
if ( imageStores == null || imageStores.size() == 0 ){
return null;
}
List<DataStore> stores = new ArrayList<DataStore>();
for (DataStore store : imageStores){
// check if the template is stored there
List<TemplateDataStoreVO> storeTmpl = this._tmplStoreDao.listByTemplateStore(templateId, store.getId());
if ( storeTmpl != null && storeTmpl.size() > 0 ){
stores.add(store);
}
}
return stores;
}
} }

View File

@ -140,7 +140,7 @@ CREATE TABLE `cloud`.`template_store_ref` (
INDEX `i_template_store_ref__template_id`(`template_id`) INDEX `i_template_store_ref__template_id`(`template_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
ALTER TABLE `cloud`.`vm_template` ADD COLUMN `image_data_store_id` bigint unsigned; -- ALTER TABLE `cloud`.`vm_template` ADD COLUMN `image_data_store_id` bigint unsigned;
-- Do we still need these columns? TODO, to delete them, remove FK constraints from snapshots table -- Do we still need these columns? TODO, to delete them, remove FK constraints from snapshots table
-- ALTER TABLE `cloud`.`snapshots` DROP COLUMN `swift_id`; -- ALTER TABLE `cloud`.`snapshots` DROP COLUMN `swift_id`;