Skip to content

Commit ab3d218

Browse files
committed
hide the primary storage when a user copies the snapshots
1 parent 0004cca commit ab3d218

File tree

17 files changed

+121
-33
lines changed

17 files changed

+121
-33
lines changed

api/src/main/java/com/cloud/storage/VolumeApiService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ public interface VolumeApiService {
113113

114114
Volume detachVolumeFromVM(DetachVolumeCmd cmd);
115115

116-
Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup, Map<String, String> tags, List<Long> zoneIds, List<Long> poolIds)
116+
Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup, Map<String, String> tags, List<Long> zoneIds, List<Long> poolIds, Boolean useStorageReplication)
117117
throws ResourceAllocationException;
118118

119-
Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType, List<Long> zoneIds, List<Long> poolIds) throws ResourceAllocationException;
119+
Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType, List<Long> zoneIds, Boolean useStorageReplication) throws ResourceAllocationException;
120120

121121
Volume updateVolume(long volumeId, String path, String state, Long storageId,
122122
Boolean displayVolume, Boolean deleteProtection,

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,9 @@ public class ApiConstants {
480480
public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid";
481481
public static final String SNAPSHOT_TYPE = "snapshottype";
482482
public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
483+
484+
public static final String USE_STORAGE_REPLICATION = "usestoragereplication";
485+
483486
public static final String SOURCE_CIDR_LIST = "sourcecidrlist";
484487
public static final String SOURCE_ZONE_ID = "sourcezoneid";
485488
public static final String SSL_VERIFICATION = "sslverification";

api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CopySnapshotCmd.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,14 @@ public class CopySnapshotCmd extends BaseAsyncCmd implements UserCmd {
9090
collectionType = CommandType.UUID,
9191
entityType = StoragePoolResponse.class,
9292
required = false,
93+
authorized = RoleType.Admin,
9394
description = "A comma-separated list of IDs of the storage pools in other zones in which the snapshot will be made available. " +
9495
"The snapshot will always be made available in the zone in which the volume is present. Currently supported for StorPool only")
9596
protected List<Long> storagePoolIds;
9697

98+
@Parameter (name = ApiConstants.USE_STORAGE_REPLICATION, type=CommandType.BOOLEAN, required = false, description = "This parameter enables the option the snapshot to be copied to supported primary storage")
99+
protected Boolean useStorageReplication;
100+
97101
/////////////////////////////////////////////////////
98102
/////////////////// Accessors ///////////////////////
99103
/////////////////////////////////////////////////////
@@ -123,6 +127,13 @@ public List<Long> getStoragePoolIds() {
123127
return storagePoolIds;
124128
}
125129

130+
public Boolean useStorageReplication() {
131+
if (useStorageReplication == null) {
132+
return false;
133+
}
134+
return useStorageReplication;
135+
}
136+
126137
@Override
127138
public String getEventType() {
128139
return EventTypes.EVENT_SNAPSHOT_COPY;
@@ -166,7 +177,7 @@ public long getEntityOwnerId() {
166177
@Override
167178
public void execute() throws ResourceUnavailableException {
168179
try {
169-
if (destZoneId == null && CollectionUtils.isEmpty(destZoneIds) && CollectionUtils.isEmpty(storagePoolIds))
180+
if (destZoneId == null && CollectionUtils.isEmpty(destZoneIds) && useStorageReplication())
170181
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
171182
"Either destzoneid or destzoneids parameters have to be specified.");
172183

api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.List;
2222
import java.util.Map;
2323

24+
import org.apache.cloudstack.acl.RoleType;
2425
import org.apache.cloudstack.api.APICommand;
2526
import org.apache.cloudstack.api.ApiCommandResourceType;
2627
import org.apache.cloudstack.api.ApiConstants;
@@ -104,11 +105,15 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
104105
type=CommandType.LIST,
105106
collectionType = CommandType.UUID,
106107
entityType = StoragePoolResponse.class,
108+
authorized = RoleType.Admin,
107109
description = "A comma-separated list of IDs of the storage pools in other zones in which the snapshot will be made available. " +
108110
"The snapshot will always be made available in the zone in which the volume is present.",
109111
since = "4.20.0")
110112
protected List<Long> storagePoolIds;
111113

114+
@Parameter (name = ApiConstants.USE_STORAGE_REPLICATION, type=CommandType.BOOLEAN, required = false, description = "This parameter enables the option the snapshot to be copied to supported primary storage")
115+
protected Boolean useStorageReplication;
116+
112117
private String syncObjectType = BaseAsyncCmd.snapshotHostSyncObject;
113118

114119
// ///////////////////////////////////////////////////
@@ -175,6 +180,13 @@ public List<Long> getStoragePoolIds() {
175180
return storagePoolIds;
176181
}
177182

183+
public Boolean useStorageReplication() {
184+
if (useStorageReplication == null) {
185+
return false;
186+
}
187+
return useStorageReplication;
188+
}
189+
178190
// ///////////////////////////////////////////////////
179191
// ///////////// API Implementation///////////////////
180192
// ///////////////////////////////////////////////////
@@ -223,7 +235,7 @@ public ApiCommandResourceType getApiResourceType() {
223235

224236
@Override
225237
public void create() throws ResourceAllocationException {
226-
Snapshot snapshot = _volumeService.allocSnapshot(getVolumeId(), getPolicyId(), getSnapshotName(), getLocationType(), getZoneIds(), getStoragePoolIds());
238+
Snapshot snapshot = _volumeService.allocSnapshot(getVolumeId(), getPolicyId(), getSnapshotName(), getLocationType(), getZoneIds(), useStorageReplication());
227239
if (snapshot != null) {
228240
setEntityId(snapshot.getId());
229241
setEntityUuid(snapshot.getUuid());
@@ -237,7 +249,7 @@ public void execute() {
237249
Snapshot snapshot;
238250
try {
239251
snapshot =
240-
_volumeService.takeSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId()), getQuiescevm(), getLocationType(), getAsyncBackup(), getTags(), getZoneIds(), getStoragePoolIds());
252+
_volumeService.takeSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId()), getQuiescevm(), getLocationType(), getAsyncBackup(), getTags(), getZoneIds(), getStoragePoolIds(), useStorageReplication());
241253

242254
if (snapshot != null) {
243255
SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
@@ -257,7 +269,7 @@ public void execute() {
257269
}
258270
}
259271

260-
private Snapshot.LocationType getLocationType() {
272+
public Snapshot.LocationType getLocationType() {
261273

262274
if (Snapshot.LocationType.values() == null || Snapshot.LocationType.values().length == 0 || locationType == null) {
263275
return null;

api/src/test/java/org/apache/cloudstack/api/command/test/CreateSnapshotCmdTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public void testCreateSuccess() {
9393
Snapshot snapshot = Mockito.mock(Snapshot.class);
9494
try {
9595
Mockito.when(volumeApiService.takeSnapshot(nullable(Long.class), nullable(Long.class), isNull(),
96-
nullable(Account.class), nullable(Boolean.class), nullable(Snapshot.LocationType.class), nullable(Boolean.class), nullable(Map.class), nullable(List.class), nullable(List.class))).thenReturn(snapshot);
96+
nullable(Account.class), nullable(Boolean.class), nullable(Snapshot.LocationType.class), nullable(Boolean.class), nullable(Map.class), nullable(List.class), nullable(List.class), Mockito.anyBoolean())).thenReturn(snapshot);
9797

9898
} catch (Exception e) {
9999
Assert.fail("Received exception when success expected " + e.getMessage());
@@ -126,7 +126,7 @@ public void testCreateFailure() {
126126

127127
try {
128128
Mockito.when(volumeApiService.takeSnapshot(nullable(Long.class), nullable(Long.class), nullable(Long.class),
129-
nullable(Account.class), nullable(Boolean.class), nullable(Snapshot.LocationType.class), nullable(Boolean.class), any(), Mockito.anyList(), Mockito.anyList())).thenReturn(null);
129+
nullable(Account.class), nullable(Boolean.class), nullable(Snapshot.LocationType.class), nullable(Boolean.class), any(), Mockito.anyList(), Mockito.anyList(), Mockito.anyBoolean())).thenReturn(null);
130130
} catch (Exception e) {
131131
Assert.fail("Received exception when success expected " + e.getMessage());
132132
}

api/src/test/java/org/apache/cloudstack/api/command/user/snapshot/CopySnapshotCmdTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,12 @@ public void testGetDestZoneIdWithBothParams() {
8787

8888
@Test (expected = ServerApiException.class)
8989
public void testExecuteWrongNoParams() {
90+
UUIDManager uuidManager = Mockito.mock(UUIDManager.class);
91+
SnapshotApiService snapshotApiService = Mockito.mock(SnapshotApiService.class);
9092
final CopySnapshotCmd cmd = new CopySnapshotCmd();
93+
cmd._uuidMgr = uuidManager;
94+
cmd._snapshotService = snapshotApiService;
95+
9196
try {
9297
cmd.execute();
9398
} catch (ResourceUnavailableException e) {

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,7 @@ Pair<List<Long>, Integer> searchForIdsAndCount(Long storagePoolId, String storag
168168
List<StoragePoolVO> listByIds(List<Long> ids);
169169

170170
List<StoragePoolVO> findStoragePoolsByEmptyStorageAccessGroups(Long dcId, Long podId, Long clusterId, ScopeType scope, HypervisorType hypervisorType);
171+
172+
List<StoragePoolVO> findPoolsByStorageTypeAndZone(Storage.StoragePoolType storageType, Long zoneId);
173+
171174
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,14 @@ public List<StoragePoolVO> listByIds(List<Long> ids) {
916916
return listBy(sc);
917917
}
918918

919+
@Override
920+
public List<StoragePoolVO> findPoolsByStorageTypeAndZone(Storage.StoragePoolType storageType, Long zoneId) {
921+
SearchCriteria<StoragePoolVO> sc = AllFieldSearch.create();
922+
sc.setParameters("poolType", storageType);
923+
sc.addAnd("dataCenterId", Op.EQ, zoneId);
924+
return listBy(sc);
925+
}
926+
919927
private SearchCriteria<StoragePoolVO> createStoragePoolSearchCriteria(Long storagePoolId, String storagePoolName,
920928
Long zoneId, String path, Long podId, Long clusterId, Long hostId, String address, ScopeType scopeType,
921929
StoragePoolStatus status, String keyword, String storageAccessGroup) {

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ private boolean deleteSnapshotFromDbIfNeeded(SnapshotVO snapshotVO, Long zoneId)
364364
!Snapshot.State.Destroying.equals(snapshotVO.getState())) {
365365
throw new InvalidParameterValueException(String.format("Can't delete snapshot %s due to it is in %s Status", snapshotVO, snapshotVO.getState()));
366366
}
367-
List<SnapshotDataStoreVO> storeRefs = _snapshotStoreDao.listBySnapshot(snapshotId, DataStoreRole.Image);
367+
List<SnapshotDataStoreVO> storeRefs = _snapshotStoreDao.listBySnapshotAndDataStoreRole(snapshotId, DataStoreRole.Image);
368368
if (zoneId != null) {
369369
storeRefs.removeIf(ref -> !zoneId.equals(dataStoreMgr.getStoreZoneId(ref.getDataStoreId(), ref.getRole())));
370370
}

server/src/main/java/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import static com.cloud.vm.VmDetailConstants.SSH_PUBLIC_KEY;
2020

21+
22+
import com.cloud.cluster.ManagementServerHostPeerJoinVO;
2123
import java.lang.reflect.InvocationTargetException;
2224
import java.lang.reflect.Method;
2325
import java.util.ArrayList;

0 commit comments

Comments
 (0)