Add prepareTemplate command(admin only) to allow pre-loading template into primary storage

This commit is contained in:
Kelven Yang 2011-08-08 18:36:46 -07:00
parent 455f9f642c
commit 02e64f90de
6 changed files with 143 additions and 2 deletions

View File

@ -0,0 +1,86 @@
/* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.response.ListResponse;
import com.cloud.api.response.TemplateResponse;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
@Implementation(responseObject=TemplateResponse.class, description="load template into primary storage")
public class PrepareTemplateCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(PrepareTemplateCmd.class.getName());
private static final String s_name = "preparetemplateresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.ZONE_ID, required=true, type=CommandType.LONG, description="zone ID of the template to be prepared in primary storage(s).")
private Long zoneId;
@Parameter(name=ApiConstants.TEMPLATE_ID, required=true, type=CommandType.LONG, description="template ID of the template to be prepared in primary storage(s).")
private Long templateId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getZoneId() {
return zoneId;
}
public Long getTemplateId() {
return templateId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {
ListResponse<TemplateResponse> response = new ListResponse<TemplateResponse>();
VirtualMachineTemplate vmTemplate = _templateService.prepareTemplate(this);
List<TemplateResponse> templateResponses = _responseGenerator.createTemplateResponses(vmTemplate.getId(), zoneId, true);
response.setResponses(templateResponses);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
}

View File

@ -26,6 +26,7 @@ import com.cloud.api.commands.DeleteTemplateCmd;
import com.cloud.api.commands.DetachIsoCmd; import com.cloud.api.commands.DetachIsoCmd;
import com.cloud.api.commands.ExtractIsoCmd; import com.cloud.api.commands.ExtractIsoCmd;
import com.cloud.api.commands.ExtractTemplateCmd; import com.cloud.api.commands.ExtractTemplateCmd;
import com.cloud.api.commands.PrepareTemplateCmd;
import com.cloud.api.commands.RegisterIsoCmd; import com.cloud.api.commands.RegisterIsoCmd;
import com.cloud.api.commands.RegisterTemplateCmd; import com.cloud.api.commands.RegisterTemplateCmd;
import com.cloud.exception.InternalErrorException; import com.cloud.exception.InternalErrorException;
@ -40,6 +41,8 @@ public interface TemplateService {
VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException; VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException;
VirtualMachineTemplate prepareTemplate(PrepareTemplateCmd cmd) ;
boolean detachIso(DetachIsoCmd cmd); boolean detachIso(DetachIsoCmd cmd);
boolean attachIso(AttachIsoCmd cmd); boolean attachIso(AttachIsoCmd cmd);

View File

@ -58,6 +58,7 @@ createSnapshotPolicy=com.cloud.api.commands.CreateSnapshotPolicyCmd;15
deleteSnapshotPolicies=com.cloud.api.commands.DeleteSnapshotPoliciesCmd;15 deleteSnapshotPolicies=com.cloud.api.commands.DeleteSnapshotPoliciesCmd;15
listSnapshotPolicies=com.cloud.api.commands.ListSnapshotPoliciesCmd;15 listSnapshotPolicies=com.cloud.api.commands.ListSnapshotPoliciesCmd;15
#### template commands #### template commands
createTemplate=com.cloud.api.commands.CreateTemplateCmd;15 createTemplate=com.cloud.api.commands.CreateTemplateCmd;15
registerTemplate=com.cloud.api.commands.RegisterTemplateCmd;15 registerTemplate=com.cloud.api.commands.RegisterTemplateCmd;15
@ -68,6 +69,7 @@ listTemplates=com.cloud.api.commands.ListTemplatesCmd;15
updateTemplatePermissions=com.cloud.api.commands.UpdateTemplatePermissionsCmd;15 updateTemplatePermissions=com.cloud.api.commands.UpdateTemplatePermissionsCmd;15
listTemplatePermissions=com.cloud.api.commands.ListTemplatePermissionsCmd;15 listTemplatePermissions=com.cloud.api.commands.ListTemplatePermissionsCmd;15
extractTemplate=com.cloud.api.commands.ExtractTemplateCmd;15 extractTemplate=com.cloud.api.commands.ExtractTemplateCmd;15
prepareTemplate=com.cloud.api.commands.PrepareTemplateCmd;1
#### iso commands #### iso commands
attachIso=com.cloud.api.commands.AttachIsoCmd;15 attachIso=com.cloud.api.commands.AttachIsoCmd;15

View File

@ -54,6 +54,7 @@ public enum Config {
StorageStatsInterval("Storage", ManagementServer.class, String.class, "storage.stats.interval", "60000", "The interval (in milliseconds) when storage stats (per host) are retrieved from agents.", null), StorageStatsInterval("Storage", ManagementServer.class, String.class, "storage.stats.interval", "60000", "The interval (in milliseconds) when storage stats (per host) are retrieved from agents.", null),
MaxVolumeSize("Storage", ManagementServer.class, Integer.class, "storage.max.volume.size", "2000", "The maximum size for a volume (in GB).", null), MaxVolumeSize("Storage", ManagementServer.class, Integer.class, "storage.max.volume.size", "2000", "The maximum size for a volume (in GB).", null),
TotalRetries("Storage", AgentManager.class, Integer.class, "total.retries", "4", "The number of times each command sent to a host should be retried in case of failure.", null), TotalRetries("Storage", AgentManager.class, Integer.class, "total.retries", "4", "The number of times each command sent to a host should be retried in case of failure.", null),
StoragePoolMaxWaitSeconds("Storage", ManagementServer.class, Integer.class, "storage.pool.max.waitseconds", "3600", "Timeout (in seconds) to synchronize storage pool operations.", null),
// Network // Network
NetworkLBHaproxyStatsVisbility("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.visibility", "global", "Load Balancer(haproxy) stats visibilty, it can be global,guest-network,disabled", null), NetworkLBHaproxyStatsVisbility("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.visibility", "global", "Load Balancer(haproxy) stats visibilty, it can be global,guest-network,disabled", null),

View File

@ -25,6 +25,8 @@ import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.ejb.Local; import javax.ejb.Local;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
@ -43,10 +45,12 @@ import com.cloud.api.commands.DeleteTemplateCmd;
import com.cloud.api.commands.DetachIsoCmd; import com.cloud.api.commands.DetachIsoCmd;
import com.cloud.api.commands.ExtractIsoCmd; import com.cloud.api.commands.ExtractIsoCmd;
import com.cloud.api.commands.ExtractTemplateCmd; import com.cloud.api.commands.ExtractTemplateCmd;
import com.cloud.api.commands.PrepareTemplateCmd;
import com.cloud.api.commands.RegisterIsoCmd; import com.cloud.api.commands.RegisterIsoCmd;
import com.cloud.api.commands.RegisterTemplateCmd; import com.cloud.api.commands.RegisterTemplateCmd;
import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobVO; import com.cloud.async.AsyncJobVO;
import com.cloud.configuration.Config;
import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.ResourceCount.ResourceType;
import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter;
@ -74,6 +78,7 @@ import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.Upload; import com.cloud.storage.Upload;
import com.cloud.storage.Upload.Type; import com.cloud.storage.Upload.Type;
@ -111,6 +116,7 @@ import com.cloud.utils.component.Adapters;
import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.component.Inject; import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager; import com.cloud.utils.component.Manager;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
@ -160,6 +166,9 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe
@Inject HypervisorGuruManager _hvGuruMgr; @Inject HypervisorGuruManager _hvGuruMgr;
protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch; protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch;
int _storagePoolMaxWaitSeconds = 3600;
ExecutorService _preloadExecutor;
@Inject (adapter=TemplateAdapter.class) @Inject (adapter=TemplateAdapter.class)
protected Adapters<TemplateAdapter> _adapters; protected Adapters<TemplateAdapter> _adapters;
@ -221,6 +230,17 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe
return extract(account, templateId, url, zoneId, mode, eventId, false, null, _asyncMgr); return extract(account, templateId, url, zoneId, mode, eventId, false, null, _asyncMgr);
} }
@Override
public VirtualMachineTemplate prepareTemplate(PrepareTemplateCmd cmd) {
VMTemplateVO vmTemplate = _tmpltDao.findById(cmd.getTemplateId());
if(vmTemplate == null)
throw new InvalidParameterValueException("Unable to find template " + cmd.getTemplateId());
prepareTemplateInAllStoragePools(vmTemplate, cmd.getZoneId());
return vmTemplate;
}
private Long extract(Account account, Long templateId, String url, Long zoneId, String mode, Long eventId, boolean isISO, AsyncJobVO job, AsyncJobManager mgr) { private Long extract(Account account, Long templateId, String url, Long zoneId, String mode, Long eventId, boolean isISO, AsyncJobVO job, AsyncJobManager mgr) {
String desc = "template"; String desc = "template";
if (isISO) { if (isISO) {
@ -330,6 +350,32 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe
} }
} }
public void prepareTemplateInAllStoragePools(final VMTemplateVO template, long zoneId) {
List<StoragePoolVO> pools = _poolDao.listPoolsByStatus(StoragePoolStatus.Up);
for(final StoragePoolVO pool : pools) {
if(pool.getDataCenterId() == zoneId) {
s_logger.info("Schedule to preload template " + template.getId() + " into primary storage " + pool.getId());
this._preloadExecutor.execute(new Runnable() {
public void run() {
try {
reallyRun();
} catch(Throwable e) {
s_logger.warn("Unexpected exception ", e);
}
}
private void reallyRun() {
s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId());
prepareTemplateForCreate(template, pool);
s_logger.info("End of preloading template " + template.getId() + " into primary storage " + pool.getId());
}
});
} else {
s_logger.info("Skip loading template " + template.getId() + " into primary storage " + pool.getId() + " as pool zone " + pool.getDataCenterId() + " is ");
}
}
}
@Override @DB @Override @DB
public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, StoragePool pool) { public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, StoragePool pool) {
template = _tmpltDao.findById(template.getId(), true); template = _tmpltDao.findById(template.getId(), true);
@ -391,7 +437,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe
List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up); List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up);
templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, 1200); 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);
} }
@ -699,6 +745,8 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe
HostSearch.done(); HostSearch.done();
HostTemplateStatesSearch.done(); HostTemplateStatesSearch.done();
_storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
_preloadExecutor = Executors.newFixedThreadPool(8, new NamedThreadFactory("Template-Preloader"));
return false; return false;
} }

View File

@ -16,3 +16,4 @@ ALTER TABLE `cloud`.`cluster` ADD COLUMN `managed_state` varchar(32) NOT NULL D
ALTER TABLE `cloud`.`host` MODIFY `storage_ip_address` char(40); ALTER TABLE `cloud`.`host` MODIFY `storage_ip_address` char(40);
INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.redundantrouter', 'false', 'enable/disable redundant virtual router'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.redundantrouter', 'false', 'enable/disable redundant virtual router');
INSERT IGNORE INTO configuration VALUES ('Storage', 'DEFAULT', 'management-server', 'storage.pool.max.waitseconds', '3600', 'Timeout (in seconds) to synchronize storage pool operations.');