Skip to content

Commit 5aeca64

Browse files
committed
make create template from volume/snapshot work
1 parent ac1b75d commit 5aeca64

10 files changed

Lines changed: 404 additions & 38 deletions

File tree

core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.apache.cloudstack.storage.command.DownloadCommand;
5454
import org.apache.cloudstack.storage.command.DownloadProgressCommand;
5555
import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType;
56+
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
5657
import org.apache.cloudstack.storage.to.TemplateObjectTO;
5758
import org.apache.commons.lang.StringUtils;
5859
import org.apache.log4j.Logger;
@@ -103,17 +104,22 @@
103104
import com.cloud.exception.InternalErrorException;
104105
import com.cloud.host.Host;
105106
import com.cloud.host.Host.Type;
107+
import com.cloud.hypervisor.Hypervisor.HypervisorType;
106108
import com.cloud.resource.ServerResourceBase;
107109
import com.cloud.storage.DataStoreRole;
108110
import com.cloud.storage.StorageLayer;
109111
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
110112
import com.cloud.storage.template.DownloadManager;
111113
import com.cloud.storage.template.DownloadManagerImpl;
112114
import com.cloud.storage.template.DownloadManagerImpl.ZfsPathParser;
115+
import com.cloud.storage.template.Processor.FormatInfo;
116+
import com.cloud.storage.template.Processor;
117+
import com.cloud.storage.template.QCOW2Processor;
113118
import com.cloud.storage.template.TemplateLocation;
114119
import com.cloud.storage.template.TemplateProp;
115120
import com.cloud.storage.template.UploadManager;
116121
import com.cloud.storage.template.UploadManagerImpl;
122+
import com.cloud.storage.template.VhdProcessor;
117123
import com.cloud.utils.NumbersUtil;
118124
import com.cloud.utils.S3Utils;
119125
import com.cloud.utils.S3Utils.FileNamingStrategy;
@@ -161,6 +167,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
161167
final private String _parent = "/mnt/SecStorage";
162168
final private String _tmpltDir = "/var/cloudstack/template";
163169
final private String _tmpltpp = "template.properties";
170+
private String createTemplateFromSnapshotXenScript;
164171

165172
@Override
166173
public void disconnected() {
@@ -280,35 +287,103 @@ public String determineFileName(final String key) {
280287
return new CopyCmdAnswer(errMsg);
281288
}
282289
}
290+
291+
292+
protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) {
293+
String srcMountPoint = this.getRootDir(srcDataStore.getUrl());
294+
String snapshotPath = srcData.getPath();
295+
int index = snapshotPath.lastIndexOf("/");
296+
String snapshotName = snapshotPath.substring(index + 1);
297+
if (!snapshotName.startsWith("VHD-") && !snapshotName.endsWith(".vhd")) {
298+
snapshotName = snapshotName + ".vhd";
299+
}
300+
snapshotPath = snapshotPath.substring(0, index);
301+
snapshotPath = srcMountPoint + snapshotPath;
302+
String destMountPoint = this.getRootDir(destDataStore.getUrl());
303+
String destPath = destMountPoint + destData.getPath();
283304

284-
protected Answer copyFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO srcImageStore,
305+
String errMsg = null;
306+
try {
307+
this._storage.mkdir(destPath);
308+
309+
String templateUuid = UUID.randomUUID().toString();
310+
String templateName = templateUuid + ".vhd";
311+
Script command = new Script(this.createTemplateFromSnapshotXenScript, cmd.getWait(), s_logger);
312+
command.add("-p", snapshotPath);
313+
command.add("-s", snapshotName);
314+
command.add("-n", templateName);
315+
command.add("-t", destPath);
316+
command.execute();
317+
318+
Map<String, Object> params = new HashMap<String, Object>();
319+
params.put(StorageLayer.InstanceConfigKey, _storage);
320+
Processor processor = new VhdProcessor();
321+
322+
processor.configure("Vhd Processor", params);
323+
FormatInfo info = processor.process(destPath, null,
324+
templateUuid);
325+
326+
TemplateLocation loc = new TemplateLocation(_storage, destPath);
327+
loc.create(1, true, templateName);
328+
loc.addFormat(info);
329+
loc.save();
330+
331+
TemplateObjectTO newTemplate = new TemplateObjectTO();
332+
newTemplate.setPath(destData.getPath() + File.separator + templateUuid);
333+
return new CopyCmdAnswer(newTemplate);
334+
} catch (ConfigurationException e) {
335+
s_logger.debug("Failed to create template from snapshot: " + e.toString());
336+
errMsg = e.toString();
337+
} catch (InternalErrorException e) {
338+
s_logger.debug("Failed to create template from snapshot: " + e.toString());
339+
errMsg = e.toString();
340+
} catch (IOException e) {
341+
s_logger.debug("Failed to create template from snapshot: " + e.toString());
342+
errMsg = e.toString();
343+
}
285344

286-
DataTO destData, NfsTO destImageStore) {
287-
return Answer.createUnsupportedCommandAnswer(cmd);
345+
return new CopyCmdAnswer(errMsg);
288346
}
347+
348+
protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) {
349+
350+
if (srcData.getHypervisorType() == HypervisorType.XenServer) {
351+
return copySnapshotToTemplateFromNfsToNfsXenserver(cmd, srcData, srcDataStore, destData, destDataStore);
352+
}
289353

290-
protected Answer execute(CopyCommand cmd) {
354+
return new CopyCmdAnswer("");
355+
}
356+
357+
protected Answer createTemplateFromSnapshot(CopyCommand cmd) {
291358
DataTO srcData = cmd.getSrcTO();
292359
DataTO destData = cmd.getDestTO();
293360
DataStoreTO srcDataStore = srcData.getDataStore();
294361
DataStoreTO destDataStore = destData.getDataStore();
295-
296-
if (srcDataStore.getRole() == DataStoreRole.Image && destDataStore.getRole() == DataStoreRole.ImageCache) {
297-
298-
if (!(destDataStore instanceof NfsTO)) {
299-
s_logger.debug("only support nfs as cache storage");
362+
if (srcDataStore.getRole() == DataStoreRole.Image || srcDataStore.getRole() == DataStoreRole.ImageCache) {
363+
if (!(srcDataStore instanceof NfsTO)) {
364+
s_logger.debug("only support nfs storage as src, when create template from snapshot");
300365
return Answer.createUnsupportedCommandAnswer(cmd);
301366
}
302-
303-
if (srcDataStore instanceof S3TO) {
304-
return copyFromS3ToNfs(cmd, srcData, (S3TO) srcDataStore, destData, (NfsTO) destDataStore);
305-
} else if (srcDataStore instanceof SwiftTO) {
306-
return copyFromSwiftToNfs(cmd, srcData, (SwiftTO) srcDataStore, destData, (NfsTO) destDataStore);
307-
} else {
308-
return Answer.createUnsupportedCommandAnswer(cmd);
367+
368+
if (destDataStore instanceof NfsTO){
369+
return copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO)srcData, (NfsTO)srcDataStore, (TemplateObjectTO)destData, (NfsTO)destDataStore);
309370
}
310371

311372
}
373+
return new CopyCmdAnswer("");
374+
}
375+
376+
protected Answer execute(CopyCommand cmd) {
377+
DataTO srcData = cmd.getSrcTO();
378+
DataTO destData = cmd.getDestTO();
379+
DataStoreTO srcDataStore = srcData.getDataStore();
380+
DataStoreTO destDataStore = destData.getDataStore();
381+
382+
if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) {
383+
return createTemplateFromSnapshot(cmd);
384+
}
385+
386+
312387
return Answer.createUnsupportedCommandAnswer(cmd);
313388
}
314389

@@ -1652,6 +1727,11 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
16521727
if (_configIpFirewallScr != null) {
16531728
s_logger.info("_configIpFirewallScr found in " + _configIpFirewallScr);
16541729
}
1730+
1731+
createTemplateFromSnapshotXenScript = Script.findScript(getDefaultScriptsDir(), "create_privatetemplate_from_snapshot_xen.sh");
1732+
if (createTemplateFromSnapshotXenScript == null) {
1733+
throw new ConfigurationException("create_privatetemplate_from_snapshot_xen.sh not found in " + getDefaultScriptsDir());
1734+
}
16551735

16561736
_role = (String) params.get("role");
16571737
if (_role == null)

engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
66

77
import com.cloud.agent.api.to.DataStoreTO;
8+
import com.cloud.hypervisor.Hypervisor.HypervisorType;
89

910
public class SnapshotObjectTO implements DataTO {
1011
private String path;
@@ -13,6 +14,7 @@ public class SnapshotObjectTO implements DataTO {
1314
private DataStoreTO dataStore;
1415
private String vmName;
1516
private String name;
17+
private HypervisorType hypervisorType;
1618
private long id;
1719

1820
public SnapshotObjectTO() {
@@ -29,6 +31,7 @@ public SnapshotObjectTO(SnapshotInfo snapshot) {
2931
}
3032
this.dataStore = snapshot.getDataStore().getTO();
3133
this.setName(snapshot.getName());
34+
this.hypervisorType = snapshot.getHypervisorType();
3235
}
3336

3437
@Override
@@ -89,4 +92,12 @@ public String getName() {
8992
public void setName(String name) {
9093
this.name = name;
9194
}
95+
96+
public HypervisorType getHypervisorType() {
97+
return hypervisorType;
98+
}
99+
100+
public void setHypervisorType(HypervisorType hypervisorType) {
101+
this.hypervisorType = hypervisorType;
102+
}
92103
}

engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ protected Answer createTemplateFromSnapshot(DataObject srcData,
327327
.parseInt(Config.CreatePrivateTemplateFromSnapshotWait
328328
.getDefaultValue()));
329329

330-
if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
330+
if (needCacheStorage(srcData, destData)) {
331331
SnapshotInfo snapshot = (SnapshotInfo)srcData;
332332
srcData = cacheSnapshotChain(snapshot);
333333
}

engine/storage/integration-test/test/org/apache/cloudstack/storage/test/CloudStackTestNGBase.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ protected void setup(String hostuuid, String gateway, String cidr,
9494
this.s3TemplateBucket = s3_template_bucket;
9595
this.s3UseHttps = Boolean.parseBoolean(s3_usehttps);
9696
this.scriptPath = scriptPath;
97+
if (this.scriptPath != null) {
98+
System.setProperty("paths.script", this.getScriptPath());
99+
}
97100
}
98101

99102
protected String getHostGuid() {

engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
3030
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
3131
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
32+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
3233
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
3334
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
3435
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
@@ -45,6 +46,8 @@
4546
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
4647
import org.apache.cloudstack.engine.subsystem.api.storage.type.RootDisk;
4748
import org.apache.cloudstack.framework.async.AsyncCallFuture;
49+
import org.apache.cloudstack.storage.LocalHostEndpoint;
50+
import org.apache.cloudstack.storage.MockLocalNfsSecondaryStorageResource;
4851
import org.apache.cloudstack.storage.RemoteHostEndPoint;
4952
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
5053
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
@@ -144,6 +147,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
144147
SnapshotDao snapshotDao;
145148
@Inject
146149
EndPointSelector epSelector;
150+
147151
long primaryStoreId;
148152
VMTemplateVO image;
149153
String imageStoreName = "testImageStore";
@@ -196,7 +200,7 @@ public void setUp() {
196200
imageStore = new ImageStoreVO();
197201
imageStore.setName(imageStoreName);
198202
imageStore.setDataCenterId(dcId);
199-
imageStore.setProviderName("CloudStack ImageStore Provider");
203+
imageStore.setProviderName(DataStoreProvider.NFS_IMAGE);
200204
imageStore.setRole(DataStoreRole.Image);
201205
imageStore.setUrl(this.getSecondaryStorage());
202206
imageStore.setUuid(UUID.randomUUID().toString());
@@ -301,7 +305,7 @@ public DataStore createPrimaryDataStore() {
301305
pool.setPoolType(StoragePoolType.NetworkFilesystem);
302306
pool.setPodId(podId);
303307
pool.setScope(ScopeType.CLUSTER);
304-
pool.setStorageProviderName("cloudstack primary data store provider");
308+
pool.setStorageProviderName(DataStoreProvider.DEFAULT_PRIMARY);
305309
pool = this.primaryStoreDao.persist(pool);
306310
DataStore store = this.dataStoreMgr.getPrimaryDataStore(pool.getId());
307311
return store;
@@ -359,15 +363,49 @@ public void createSnapshot() {
359363
}
360364
}
361365
}
362-
363-
//@Test
364-
public void testCreateDataDisk() {
365-
DataStore primaryStore = createPrimaryDataStore();
366-
primaryStoreId = primaryStore.getId();
367-
primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId);
368-
VolumeVO volume = createVolume(null, primaryStore.getId());
369-
VolumeInfo volInfo = this.volFactory.getVolume(volume.getId());
370-
this.volumeService.createVolumeAsync(volInfo, primaryStore);
366+
367+
private VMTemplateVO createTemplateInDb() {
368+
image = new VMTemplateVO();
369+
image.setTemplateType(TemplateType.USER);
370+
371+
image.setUniqueName(UUID.randomUUID().toString());
372+
image.setName(UUID.randomUUID().toString());
373+
image.setPublicTemplate(true);
374+
image.setFeatured(true);
375+
image.setRequiresHvm(true);
376+
image.setBits(64);
377+
image.setFormat(Storage.ImageFormat.VHD);
378+
image.setEnablePassword(true);
379+
image.setEnableSshKey(true);
380+
image.setGuestOSId(1);
381+
image.setBootable(true);
382+
image.setPrepopulate(true);
383+
image.setCrossZones(true);
384+
image.setExtractable(true);
385+
image = imageDataDao.persist(image);
386+
return image;
387+
}
388+
389+
@Test
390+
public void createTemplateFromSnapshot() {
391+
VolumeInfo vol = createCopyBaseImage();
392+
SnapshotVO snapshotVO = createSnapshotInDb(vol);
393+
SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore());
394+
boolean result = false;
395+
for (SnapshotStrategy strategy : this.snapshotStrategies) {
396+
if (strategy.canHandle(snapshot)) {
397+
snapshot = strategy.takeSnapshot(snapshot);
398+
result = true;
399+
}
400+
}
401+
402+
AssertJUnit.assertTrue(result);
403+
LocalHostEndpoint ep = new LocalHostEndpoint();
404+
ep.setResource(new MockLocalNfsSecondaryStorageResource());
405+
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep);
406+
VMTemplateVO templateVO = createTemplateInDb();
407+
TemplateInfo tmpl = this.templateFactory.getTemplate(templateVO.getId());
408+
DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
409+
this.imageService.createTemplateFromSnapshotAsync(snapshot, tmpl, imageStore);
371410
}
372-
373411
}

engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TemplateTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public class TemplateTest extends CloudStackTestNGBase {
6868
@Test(priority = -1)
6969
public void setUp() {
7070
ComponentContext.initComponentsLifeCycle();
71-
System.setProperty("paths.script", this.getScriptPath());
71+
7272
//create data center
7373
DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24",
7474
null, null, NetworkType.Basic, null, null, true, true, null, null);

engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,55 @@ public void testDeleteDisk() {
379379
}
380380

381381
}
382+
383+
private VMTemplateVO createTemplateInDb() {
384+
image = new VMTemplateVO();
385+
image.setTemplateType(TemplateType.USER);
386+
387+
image.setUniqueName(UUID.randomUUID().toString());
388+
image.setName(UUID.randomUUID().toString());
389+
image.setPublicTemplate(true);
390+
image.setFeatured(true);
391+
image.setRequiresHvm(true);
392+
image.setBits(64);
393+
image.setFormat(Storage.ImageFormat.VHD);
394+
image.setEnablePassword(true);
395+
image.setEnableSshKey(true);
396+
image.setGuestOSId(1);
397+
image.setBootable(true);
398+
image.setPrepopulate(true);
399+
image.setCrossZones(true);
400+
image.setExtractable(true);
401+
image = imageDataDao.persist(image);
402+
return image;
403+
}
404+
405+
@Test
406+
public void testCreateTemplateFromVolume() {
407+
DataStore primaryStore = createPrimaryDataStore();
408+
primaryStoreId = primaryStore.getId();
409+
primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId);
410+
VolumeVO volume = createVolume(null, primaryStore.getId());
411+
VolumeInfo volInfo = this.volFactory.getVolume(volume.getId());
412+
AsyncCallFuture<VolumeApiResult> future = this.volumeService.createVolumeAsync(volInfo, primaryStore);
413+
try {
414+
VolumeApiResult result = future.get();
415+
416+
AssertJUnit.assertTrue(result.isSuccess());
417+
volInfo = result.getVolume();
418+
VMTemplateVO templateVO = createTemplateInDb();
419+
TemplateInfo tmpl = this.templateFactory.getTemplate(templateVO.getId());
420+
DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
421+
422+
this.imageService.createTemplateFromVolumeAsync(volInfo, tmpl, imageStore);
423+
} catch (InterruptedException e) {
424+
// TODO Auto-generated catch block
425+
e.printStackTrace();
426+
} catch (ExecutionException e) {
427+
// TODO Auto-generated catch block
428+
e.printStackTrace();
429+
}
430+
431+
432+
}
382433
}

0 commit comments

Comments
 (0)