Skip to content

Commit 02e64f9

Browse files
author
Kelven Yang
committed
Add prepareTemplate command(admin only) to allow pre-loading template into primary storage
1 parent 455f9f6 commit 02e64f9

6 files changed

Lines changed: 143 additions & 2 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
2+
*
3+
* This software is licensed under the GNU General Public License v3 or later.
4+
*
5+
* It is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or any later version.
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
package com.cloud.api.commands;
18+
19+
import java.util.List;
20+
21+
import org.apache.log4j.Logger;
22+
23+
import com.cloud.api.ApiConstants;
24+
import com.cloud.api.BaseCmd;
25+
import com.cloud.api.Implementation;
26+
import com.cloud.api.Parameter;
27+
import com.cloud.api.response.ListResponse;
28+
import com.cloud.api.response.TemplateResponse;
29+
import com.cloud.template.VirtualMachineTemplate;
30+
import com.cloud.user.Account;
31+
32+
@Implementation(responseObject=TemplateResponse.class, description="load template into primary storage")
33+
public class PrepareTemplateCmd extends BaseCmd {
34+
public static final Logger s_logger = Logger.getLogger(PrepareTemplateCmd.class.getName());
35+
36+
private static final String s_name = "preparetemplateresponse";
37+
38+
/////////////////////////////////////////////////////
39+
//////////////// API parameters /////////////////////
40+
/////////////////////////////////////////////////////
41+
42+
@Parameter(name=ApiConstants.ZONE_ID, required=true, type=CommandType.LONG, description="zone ID of the template to be prepared in primary storage(s).")
43+
private Long zoneId;
44+
45+
@Parameter(name=ApiConstants.TEMPLATE_ID, required=true, type=CommandType.LONG, description="template ID of the template to be prepared in primary storage(s).")
46+
private Long templateId;
47+
48+
49+
/////////////////////////////////////////////////////
50+
/////////////////// Accessors ///////////////////////
51+
/////////////////////////////////////////////////////
52+
53+
public Long getZoneId() {
54+
return zoneId;
55+
}
56+
57+
public Long getTemplateId() {
58+
return templateId;
59+
}
60+
61+
/////////////////////////////////////////////////////
62+
/////////////// API Implementation///////////////////
63+
/////////////////////////////////////////////////////
64+
65+
@Override
66+
public String getCommandName() {
67+
return s_name;
68+
}
69+
70+
@Override
71+
public long getEntityOwnerId() {
72+
return Account.ACCOUNT_ID_SYSTEM;
73+
}
74+
75+
@Override
76+
public void execute() {
77+
ListResponse<TemplateResponse> response = new ListResponse<TemplateResponse>();
78+
79+
VirtualMachineTemplate vmTemplate = _templateService.prepareTemplate(this);
80+
List<TemplateResponse> templateResponses = _responseGenerator.createTemplateResponses(vmTemplate.getId(), zoneId, true);
81+
response.setResponses(templateResponses);
82+
response.setResponseName(getCommandName());
83+
this.setResponseObject(response);
84+
}
85+
}
86+

api/src/com/cloud/template/TemplateService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.cloud.api.commands.DetachIsoCmd;
2727
import com.cloud.api.commands.ExtractIsoCmd;
2828
import com.cloud.api.commands.ExtractTemplateCmd;
29+
import com.cloud.api.commands.PrepareTemplateCmd;
2930
import com.cloud.api.commands.RegisterIsoCmd;
3031
import com.cloud.api.commands.RegisterTemplateCmd;
3132
import com.cloud.exception.InternalErrorException;
@@ -39,6 +40,8 @@ public interface TemplateService {
3940
VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws IllegalArgumentException, ResourceAllocationException;
4041

4142
VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException;
43+
44+
VirtualMachineTemplate prepareTemplate(PrepareTemplateCmd cmd) ;
4245

4346
boolean detachIso(DetachIsoCmd cmd);
4447

client/tomcatconf/commands.properties.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ createSnapshotPolicy=com.cloud.api.commands.CreateSnapshotPolicyCmd;15
5858
deleteSnapshotPolicies=com.cloud.api.commands.DeleteSnapshotPoliciesCmd;15
5959
listSnapshotPolicies=com.cloud.api.commands.ListSnapshotPoliciesCmd;15
6060

61+
6162
#### template commands
6263
createTemplate=com.cloud.api.commands.CreateTemplateCmd;15
6364
registerTemplate=com.cloud.api.commands.RegisterTemplateCmd;15
@@ -68,6 +69,7 @@ listTemplates=com.cloud.api.commands.ListTemplatesCmd;15
6869
updateTemplatePermissions=com.cloud.api.commands.UpdateTemplatePermissionsCmd;15
6970
listTemplatePermissions=com.cloud.api.commands.ListTemplatePermissionsCmd;15
7071
extractTemplate=com.cloud.api.commands.ExtractTemplateCmd;15
72+
prepareTemplate=com.cloud.api.commands.PrepareTemplateCmd;1
7173

7274
#### iso commands
7375
attachIso=com.cloud.api.commands.AttachIsoCmd;15

server/src/com/cloud/configuration/Config.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public enum Config {
5454
StorageStatsInterval("Storage", ManagementServer.class, String.class, "storage.stats.interval", "60000", "The interval (in milliseconds) when storage stats (per host) are retrieved from agents.", null),
5555
MaxVolumeSize("Storage", ManagementServer.class, Integer.class, "storage.max.volume.size", "2000", "The maximum size for a volume (in GB).", null),
5656
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),
57+
StoragePoolMaxWaitSeconds("Storage", ManagementServer.class, Integer.class, "storage.pool.max.waitseconds", "3600", "Timeout (in seconds) to synchronize storage pool operations.", null),
5758

5859
// Network
5960
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),

server/src/com/cloud/template/TemplateManagerImpl.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.ArrayList;
2626
import java.util.List;
2727
import java.util.Map;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.Executors;
2830

2931
import javax.ejb.Local;
3032
import javax.naming.ConfigurationException;
@@ -43,10 +45,12 @@
4345
import com.cloud.api.commands.DetachIsoCmd;
4446
import com.cloud.api.commands.ExtractIsoCmd;
4547
import com.cloud.api.commands.ExtractTemplateCmd;
48+
import com.cloud.api.commands.PrepareTemplateCmd;
4649
import com.cloud.api.commands.RegisterIsoCmd;
4750
import com.cloud.api.commands.RegisterTemplateCmd;
4851
import com.cloud.async.AsyncJobManager;
4952
import com.cloud.async.AsyncJobVO;
53+
import com.cloud.configuration.Config;
5054
import com.cloud.configuration.ResourceCount.ResourceType;
5155
import com.cloud.configuration.dao.ConfigurationDao;
5256
import com.cloud.dc.DataCenter;
@@ -74,6 +78,7 @@
7478
import com.cloud.storage.StorageManager;
7579
import com.cloud.storage.StoragePool;
7680
import com.cloud.storage.StoragePoolHostVO;
81+
import com.cloud.storage.StoragePoolStatus;
7782
import com.cloud.storage.StoragePoolVO;
7883
import com.cloud.storage.Upload;
7984
import com.cloud.storage.Upload.Type;
@@ -111,6 +116,7 @@
111116
import com.cloud.utils.component.ComponentLocator;
112117
import com.cloud.utils.component.Inject;
113118
import com.cloud.utils.component.Manager;
119+
import com.cloud.utils.concurrency.NamedThreadFactory;
114120
import com.cloud.utils.db.DB;
115121
import com.cloud.utils.db.JoinBuilder;
116122
import com.cloud.utils.db.SearchBuilder;
@@ -160,6 +166,9 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe
160166
@Inject HypervisorGuruManager _hvGuruMgr;
161167
protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch;
162168

169+
int _storagePoolMaxWaitSeconds = 3600;
170+
ExecutorService _preloadExecutor;
171+
163172
@Inject (adapter=TemplateAdapter.class)
164173
protected Adapters<TemplateAdapter> _adapters;
165174

@@ -220,6 +229,17 @@ public Long extract(ExtractTemplateCmd cmd) {
220229
// FIXME: async job needs fixing
221230
return extract(account, templateId, url, zoneId, mode, eventId, false, null, _asyncMgr);
222231
}
232+
233+
@Override
234+
public VirtualMachineTemplate prepareTemplate(PrepareTemplateCmd cmd) {
235+
236+
VMTemplateVO vmTemplate = _tmpltDao.findById(cmd.getTemplateId());
237+
if(vmTemplate == null)
238+
throw new InvalidParameterValueException("Unable to find template " + cmd.getTemplateId());
239+
240+
prepareTemplateInAllStoragePools(vmTemplate, cmd.getZoneId());
241+
return vmTemplate;
242+
}
223243

224244
private Long extract(Account account, Long templateId, String url, Long zoneId, String mode, Long eventId, boolean isISO, AsyncJobVO job, AsyncJobManager mgr) {
225245
String desc = "template";
@@ -328,7 +348,33 @@ private Long extract(Account account, Long templateId, String url, Long zoneId,
328348
}else{
329349
return null;
330350
}
331-
}
351+
}
352+
353+
public void prepareTemplateInAllStoragePools(final VMTemplateVO template, long zoneId) {
354+
List<StoragePoolVO> pools = _poolDao.listPoolsByStatus(StoragePoolStatus.Up);
355+
for(final StoragePoolVO pool : pools) {
356+
if(pool.getDataCenterId() == zoneId) {
357+
s_logger.info("Schedule to preload template " + template.getId() + " into primary storage " + pool.getId());
358+
this._preloadExecutor.execute(new Runnable() {
359+
public void run() {
360+
try {
361+
reallyRun();
362+
} catch(Throwable e) {
363+
s_logger.warn("Unexpected exception ", e);
364+
}
365+
}
366+
367+
private void reallyRun() {
368+
s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId());
369+
prepareTemplateForCreate(template, pool);
370+
s_logger.info("End of preloading template " + template.getId() + " into primary storage " + pool.getId());
371+
}
372+
});
373+
} else {
374+
s_logger.info("Skip loading template " + template.getId() + " into primary storage " + pool.getId() + " as pool zone " + pool.getDataCenterId() + " is ");
375+
}
376+
}
377+
}
332378

333379
@Override @DB
334380
public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, StoragePool pool) {
@@ -391,7 +437,7 @@ public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, S
391437

392438
List<StoragePoolHostVO> vos = _poolHostDao.listByHostStatus(poolId, com.cloud.host.Status.Up);
393439

394-
templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, 1200);
440+
templateStoragePoolRef = _tmpltPoolDao.acquireInLockTable(templateStoragePoolRefId, _storagePoolMaxWaitSeconds);
395441
if (templateStoragePoolRef == null) {
396442
throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templateStoragePoolRefId);
397443
}
@@ -699,6 +745,8 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
699745
HostSearch.done();
700746
HostTemplateStatesSearch.done();
701747

748+
_storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
749+
_preloadExecutor = Executors.newFixedThreadPool(8, new NamedThreadFactory("Template-Preloader"));
702750
return false;
703751
}
704752

setup/db/db/schema-229to2210.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ ALTER TABLE `cloud`.`cluster` ADD COLUMN `managed_state` varchar(32) NOT NULL D
1616
ALTER TABLE `cloud`.`host` MODIFY `storage_ip_address` char(40);
1717

1818
INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.redundantrouter', 'false', 'enable/disable redundant virtual router');
19+
INSERT IGNORE INTO configuration VALUES ('Storage', 'DEFAULT', 'management-server', 'storage.pool.max.waitseconds', '3600', 'Timeout (in seconds) to synchronize storage pool operations.');

0 commit comments

Comments
 (0)