Skip to content

Commit 06f6b00

Browse files
author
Mike Tutkowski
committed
Snapshot support
1 parent 45611a0 commit 06f6b00

5 files changed

Lines changed: 156 additions & 13 deletions

File tree

engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
import com.cloud.host.Host;
2727

2828
public interface DataMotionStrategy {
29+
// IQN is used by the StorageSystemDataMotionStrategy to create a template from a snapshot or clone that resides on a storage system
30+
public static final String IQN = "iqn";
31+
2932
StrategyPriority canHandle(DataObject srcData, DataObject destData);
3033

3134
StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.cloudstack.storage.motion;
20+
21+
import java.util.Map;
22+
23+
import org.apache.log4j.Logger;
24+
import org.springframework.stereotype.Component;
25+
26+
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
27+
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
28+
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
29+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
30+
import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
31+
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
32+
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
33+
34+
import com.cloud.agent.api.to.VirtualMachineTO;
35+
import com.cloud.host.Host;
36+
37+
@Component
38+
public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
39+
private static final Logger s_logger = Logger.getLogger(StorageSystemDataMotionStrategy.class);
40+
41+
@Override
42+
public StrategyPriority canHandle(DataObject srcData, DataObject destData) {
43+
return StrategyPriority.DEFAULT;
44+
}
45+
46+
@Override
47+
public StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
48+
return StrategyPriority.CANT_HANDLE;
49+
}
50+
51+
@Override
52+
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
53+
54+
return null;
55+
}
56+
57+
@Override
58+
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
59+
return copyAsync(srcData, destData, null, callback);
60+
}
61+
62+
@Override
63+
public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
64+
CopyCommandResult result = new CopyCommandResult(null, null);
65+
66+
result.setResult("Unsupported operation requested for copying data.");
67+
68+
callback.complete(result);
69+
70+
return null;
71+
}
72+
}

plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
2727
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
2828
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
29+
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
2930
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
3031
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
3132
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
@@ -523,11 +524,27 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<Crea
523524

524525
long sfSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, snapshotInfo.getUuid());
525526

526-
// Now that we have successfully taken a snapshot, update the space usage in the storage_pool table (even
527-
// though storage_pool.used_bytes is likely no longer in use).
527+
long sfCloneId;
528+
String sfCloneIqn;
529+
530+
try {
531+
sfCloneId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, snapshotInfo.getUuid());
532+
533+
SolidFireUtil.SolidFireVolume sfClonedVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfCloneId);
534+
535+
sfCloneIqn = sfClonedVolume.getIqn();
536+
}
537+
catch (Exception ex) {
538+
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId);
539+
540+
throw ex;
541+
}
542+
543+
// Now that we have successfully taken a snapshot (for the purpose of reverting) and a clone (for the purpose of creating a template
544+
// and a volume), update the space usage in the storage_pool table (even though storage_pool.used_bytes is likely no longer in use).
528545
_storagePoolDao.update(storagePoolId, storagePool);
529546

530-
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize);
547+
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize, sfCloneId, sfCloneIqn);
531548

532549
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
533550

@@ -550,7 +567,7 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<Crea
550567
callback.complete(result);
551568
}
552569

553-
private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long storagePoolId, long sfSnapshotSize) {
570+
private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long storagePoolId, long sfSnapshotSize, long sfCloneId, String sfCloneIqn) {
554571
SnapshotDetailsVO accountDetail = new SnapshotDetailsVO(csSnapshotId,
555572
SolidFireUtil.SNAPSHOT_ID,
556573
String.valueOf(sfSnapshotId),
@@ -571,6 +588,20 @@ private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long st
571588
false);
572589

573590
_snapshotDetailsDao.persist(accountDetail);
591+
592+
accountDetail = new SnapshotDetailsVO(csSnapshotId,
593+
SolidFireUtil.CLONE_ID,
594+
String.valueOf(sfCloneId),
595+
false);
596+
597+
_snapshotDetailsDao.persist(accountDetail);
598+
599+
accountDetail = new SnapshotDetailsVO(csSnapshotId,
600+
DataMotionStrategy.IQN,
601+
sfCloneIqn,
602+
false);
603+
604+
_snapshotDetailsDao.persist(accountDetail);
574605
}
575606

576607
// return null for no error message
@@ -581,6 +612,7 @@ private String deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) {
581612
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
582613

583614
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, getSolidFireSnapshotId(snapshotInfo.getId()));
615+
SolidFireUtil.deleteSolidFireVolume(sfConnection, getSolidFireCloneId(snapshotInfo.getId()));
584616

585617
_snapshotDetailsDao.removeDetails(snapshotInfo.getId());
586618

@@ -608,6 +640,12 @@ private long getSolidFireSnapshotId(long csSnapshotId) {
608640
return Long.parseLong(snapshotDetails.getValue());
609641
}
610642

643+
private long getSolidFireCloneId(long csSnapshotId) {
644+
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.CLONE_ID);
645+
646+
return Long.parseLong(snapshotDetails.getValue());
647+
}
648+
611649
@Override
612650
public void revertSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CommandResult> callback) {
613651
String errMsg = null;

plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -703,10 +703,10 @@ public static void rollBackVolumeToSnapshot(SolidFireConnection sfConnection, lo
703703
verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson);
704704
}
705705

706-
public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, String cloneName) {
706+
public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, String cloneName) {
707707
final Gson gson = new GsonBuilder().create();
708708

709-
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, cloneName);
709+
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName);
710710

711711
String strCloneToCreateJson = gson.toJson(cloneToCreate);
712712

@@ -1332,16 +1332,18 @@ private static final class CloneToCreate {
13321332
private final String method = "CloneVolume";
13331333
private final CloneToCreateParams params;
13341334

1335-
private CloneToCreate(final long lVolumeId, final String cloneName) {
1336-
params = new CloneToCreateParams(lVolumeId, cloneName);
1335+
private CloneToCreate(final long lVolumeId, final long lSnapshotId, final String cloneName) {
1336+
params = new CloneToCreateParams(lVolumeId, lSnapshotId, cloneName);
13371337
}
13381338

13391339
private static final class CloneToCreateParams {
13401340
private long volumeID;
1341+
private long snapshotID;
13411342
private String name;
13421343

1343-
private CloneToCreateParams(final long lVolumeId, final String cloneName) {
1344+
private CloneToCreateParams(final long lVolumeId, final long lSnapshotId, final String cloneName) {
13441345
volumeID = lVolumeId;
1346+
snapshotID = lSnapshotId;
13451347
name = cloneName;
13461348
}
13471349
}

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.apache.cloudstack.context.CallContext;
5555
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
5656
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
57+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
5758
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
5859
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
5960
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
@@ -1376,12 +1377,20 @@ public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) t
13761377
throw new CloudRuntimeException("cannot find an image store for zone " + zoneId);
13771378
}
13781379
AsyncCallFuture<TemplateApiResult> future = null;
1380+
13791381
if (snapshotId != null) {
1380-
SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
1381-
DataStore snapStore = snapInfo.getDataStore();
1382-
if (snapStore != null) {
1383-
store = snapStore; // pick snapshot image store to create template
1382+
DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
1383+
1384+
SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole);
1385+
1386+
if (dataStoreRole == DataStoreRole.Image) {
1387+
DataStore snapStore = snapInfo.getDataStore();
1388+
1389+
if (snapStore != null) {
1390+
store = snapStore; // pick snapshot image store to create template
1391+
}
13841392
}
1393+
13851394
future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store);
13861395
} else if (volumeId != null) {
13871396
VolumeInfo volInfo = _volFactory.getVolume(volumeId);
@@ -1465,6 +1474,25 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
14651474
}
14661475
}
14671476

1477+
private DataStoreRole getDataStoreRole(Snapshot snapshot) {
1478+
long volumeId = snapshot.getVolumeId();
1479+
VolumeVO volumeVO = _volumeDao.findById(volumeId);
1480+
1481+
long storagePoolId = volumeVO.getPoolId();
1482+
DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
1483+
1484+
Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities();
1485+
1486+
String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString());
1487+
Boolean supportsStorageSystemSnapshots = new Boolean(value);
1488+
1489+
if (supportsStorageSystemSnapshots) {
1490+
return DataStoreRole.Primary;
1491+
}
1492+
1493+
return DataStoreRole.Image;
1494+
}
1495+
14681496
@Override
14691497
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true)
14701498
public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException {

0 commit comments

Comments
 (0)