Skip to content

Commit

Permalink
added option in the UI for the storage pools
Browse files Browse the repository at this point in the history
Added drop down to choose the primary storage pools to copy a snapshot
Small fixes
  • Loading branch information
slavkap committed Aug 14, 2024
1 parent dad9aa6 commit 0df6764
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.apache.cloudstack.storage.datastore.util.StorPoolUtil;
import org.apache.cloudstack.storage.datastore.util.StorPoolUtil.SpApiResponse;
import org.apache.cloudstack.storage.datastore.util.StorPoolUtil.SpConnectionDesc;
import org.apache.cloudstack.storage.snapshot.StorPoolSnapshotStrategy;
import org.apache.commons.collections.CollectionUtils;

import javax.inject.Inject;
Expand Down Expand Up @@ -379,12 +378,13 @@ protected void runInContext() {
}
if (snapshots.contains(name)) {
Long clusterId = StorPoolHelper.findClusterIdByGlobalId(StorPoolUtil.getSnapshotClusterId(name, conn), clusterDao);
conn = StorPoolSnapshotStrategy.getSpConnectionDesc(conn, clusterId);
conn = StorPoolHelper.getSpConnectionDesc(conn, clusterId);
SpApiResponse resp = StorPoolUtil.snapshotUnexport(name, location, conn);

Check warning on line 382 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java#L380-L382

Added lines #L380 - L382 were not covered by tests
if (resp.getError() == null) {
StorPoolUtil.spLog("Unexport of snapshot %s was successful", name);
recoveredSnapshots.add(snapshot.getId());

Check warning on line 385 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java#L384-L385

Added lines #L384 - L385 were not covered by tests
} else {
logger.debug(String.format("Could not recover StorPool snapshot %s", resp.getError()));
StorPoolUtil.spLog("Could not recover StorPool snapshot %s", resp.getError());

Check warning on line 387 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java#L387

Added line #L387 was not covered by tests
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,15 @@ public static boolean isPoolSupportsAllFunctionalityFromPreviousVersion(StorageP
}
return true;
}

public static StorPoolUtil.SpConnectionDesc getSpConnectionDesc(StorPoolUtil.SpConnectionDesc connectionLocal, Long clusterId) {

Check warning on line 309 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java#L309

Added line #L309 was not covered by tests

String subClusterEndPoint = StorPoolConfigurationManager.StorPoolSubclusterEndpoint.valueIn(clusterId);

Check warning on line 311 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java#L311

Added line #L311 was not covered by tests
if (StringUtils.isNotEmpty(subClusterEndPoint)) {
String host = subClusterEndPoint.split(";")[0].split("=")[1];
String token = subClusterEndPoint.split(";")[1].split("=")[1];
connectionLocal = new StorPoolUtil.SpConnectionDesc(host, token, connectionLocal.getTemplateName());

Check warning on line 315 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java#L313-L315

Added lines #L313 - L315 were not covered by tests
}
return connectionLocal;
}

Check warning on line 318 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java#L317-L318

Added lines #L317 - L318 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,8 @@ public static SpApiResponse snapshotExport(String name, String location, SpConne
public static SpApiResponse snapshotUnexport(String name, String location, SpConnectionDesc conn) {
Map<String, Object> json = new HashMap<>();
json.put("snapshot", name);
json.put("location", location);
json.put("force", true);
json.put("all", true);
return POST("SnapshotUnexport", json, conn);
}

Check warning on line 671 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java#L665-L671

Added lines #L665 - L671 were not covered by tests

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
import org.apache.cloudstack.storage.datastore.util.StorPoolUtil.SpConnectionDesc;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -196,6 +195,12 @@ public StrategyPriority canHandle(Snapshot snapshot, Long zoneId, SnapshotOperat
if (CollectionUtils.isEmpty(pools)) {
return StrategyPriority.CANT_HANDLE;
}
List<SnapshotJoinVO> snapshots = snapshotJoinDao.listBySnapshotIdAndZoneId(zoneId, snapshot.getId());

Check warning on line 198 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L198 was not covered by tests
boolean snapshotNotOnStorPool = snapshots.stream().filter(s -> s.getStoreRole().equals(DataStoreRole.Primary)).count() == 0;

if (snapshotNotOnStorPool) {
return StrategyPriority.CANT_HANDLE;

Check warning on line 202 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L202 was not covered by tests
}
for (StoragePoolVO pool : pools) {
SnapshotDataStoreVO snapshotOnPrimary = _snapshotStoreDao.findByStoreSnapshot(DataStoreRole.Primary, pool.getId(), snapshot.getId());

Check warning on line 205 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L205 was not covered by tests
if (snapshotOnPrimary != null && (snapshotOnPrimary.getState().equals(State.Ready) || snapshotOnPrimary.getState().equals(State.Created))) {
Expand Down Expand Up @@ -391,7 +396,7 @@ public void copySnapshot(DataObject snapshot, DataObject snapshotDest, AsyncComp
snapshot.getDataStore().getId(), storagePoolDetailsDao, _primaryDataStoreDao);
String snapshotName = StorPoolStorageAdaptor.getVolumeNameFromPath(srcSnapshot.getPath(), false);
Long clusterId = StorPoolHelper.findClusterIdByGlobalId(StorPoolUtil.getSnapshotClusterId("~" + snapshotName, connectionLocal), clusterDao);
connectionLocal = getSpConnectionDesc(connectionLocal, clusterId);
connectionLocal = StorPoolHelper.getSpConnectionDesc(connectionLocal, clusterId);
SpApiResponse resp = StorPoolUtil.snapshotExport("~" + snapshotName, location, connectionLocal);

Check warning on line 400 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java#L395-L400

Added lines #L395 - L400 were not covered by tests
if (resp.getError() != null) {
StorPoolUtil.spLog("Failed to export snapshot %s from %s due to %s", snapshotName, location, resp.getError());
Expand All @@ -401,6 +406,9 @@ public void copySnapshot(DataObject snapshot, DataObject snapshotDest, AsyncComp
callback.complete(res);
return;

Check warning on line 407 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java#L402-L407

Added lines #L402 - L407 were not covered by tests
}
String detail = "~" + snapshotName + ";" + location;
SnapshotDetailsVO snapshotForRecovery = new SnapshotDetailsVO(snapshot.getId(), StorPoolUtil.SP_RECOVERED_SNAPSHOT, detail, true);
_snapshotDetailsDao.persist(snapshotForRecovery);
SpConnectionDesc connectionRemote = StorPoolUtil.getSpConnection(storagePoolVO.getUuid(),
storagePoolVO.getId(), storagePoolDetailsDao, _primaryDataStoreDao);
String localLocation = StorPoolConfigurationManager.StorPoolClusterLocation
Expand All @@ -418,9 +426,7 @@ public void copySnapshot(DataObject snapshot, DataObject snapshotDest, AsyncComp
return;

Check warning on line 426 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java#L421-L426

Added lines #L421 - L426 were not covered by tests
}
StorPoolUtil.spLog("The snapshot [%s] was copied from remote", snapshotName);

Check warning on line 428 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L428 was not covered by tests
String detail = "~" + snapshotName + ";" + location;
SnapshotDetailsVO snapshotForRecovery = new SnapshotDetailsVO(snapshot.getId(), StorPoolUtil.SP_RECOVERED_SNAPSHOT, detail, true);
_snapshotDetailsDao.persist(snapshotForRecovery);

respFromRemote = StorPoolUtil.snapshotReconcile("~" + snapshotName, connectionRemote);

Check warning on line 430 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L430 was not covered by tests
if (respFromRemote.getError() != null) {
StorPoolUtil.spLog("Failed to reconcile snapshot %s from %s due to %s", snapshotName, location, respFromRemote.getError());
Expand All @@ -447,15 +453,4 @@ public void copySnapshot(DataObject snapshot, DataObject snapshotDest, AsyncComp
res.setResult(err);
callback.complete(res);
}

Check warning on line 455 in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java

View check run for this annotation

Codecov / codecov/patch

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java#L449-L455

Added lines #L449 - L455 were not covered by tests

public static SpConnectionDesc getSpConnectionDesc(SpConnectionDesc connectionLocal, Long clusterId) {

String subClusterEndPoint = StorPoolConfigurationManager.StorPoolSubclusterEndpoint.valueIn(clusterId);
if (StringUtils.isNotEmpty(subClusterEndPoint)) {
String host = subClusterEndPoint.split(";")[0].split("=")[1];
String token = subClusterEndPoint.split(";")[1].split("=")[1];
connectionLocal = new SpConnectionDesc(host, token, connectionLocal.getTemplateName());
}
return connectionLocal;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3862,6 +3862,7 @@ private boolean canCopyOnPrimary(List<Long> poolIds, VolumeInfo volume, boolean
} else {
return false;

Check warning on line 3863 in server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java#L3861-L3863

Added lines #L3861 - L3863 were not covered by tests
}
snapshotHelper.checkIfThereAreMoreThanOnePoolInTheZone(poolIds);
return true;
}

Check warning on line 3867 in server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java#L3865-L3867

Added lines #L3865 - L3867 were not covered by tests

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,7 @@ protected void validatePolicyZones(List<Long> zoneIds, List<Long> poolIds, Volum
}
}
if (hasPools) {
snapshotHelper.checkIfThereAreMoreThanOnePoolInTheZone(poolIds);

Check warning on line 956 in server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java#L956

Added line #L956 was not covered by tests
for (Long poolId : poolIds) {
getCheckedDestinationStorageForSnapshotCopy(poolId, isRootAdminCaller);
}

Check warning on line 959 in server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java#L958-L959

Added lines #L958 - L959 were not covered by tests
Expand Down Expand Up @@ -2027,6 +2028,7 @@ public Snapshot copySnapshot(CopySnapshotCmd cmd) throws StorageUnavailableExcep
throw new InvalidParameterValueException(String.format("There is no snapshot ID: %s ready on image store", snapshot.getUuid()));
}
if (canCopyBetweenStoragePools) {
snapshotHelper.checkIfThereAreMoreThanOnePoolInTheZone(storagePoolIds);
copySnapshotToPrimaryDifferentZone(storagePoolIds, snapshot);

Check warning on line 2032 in server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java#L2031-L2032

Added lines #L2031 - L2032 were not covered by tests
}
List<String> failedZones = copySnapshotToZones(snapshot, srcSecStore, new ArrayList<>(dataCenterVOs.values()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1683,15 +1683,15 @@ public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) t
if (kvmSnapshotOnlyInPrimaryStorage && keepOnPrimary) {
skipCopyToSecondary = true;

Check warning on line 1684 in server/src/main/java/com/cloud/template/TemplateManagerImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/template/TemplateManagerImpl.java#L1684

Added line #L1684 was not covered by tests
}
if (dataStoreRole == DataStoreRole.Image || !skipCopyToSecondary) {
if (dataStoreRole == DataStoreRole.Image) {
snapInfo = snapshotHelper.backupSnapshotToSecondaryStorageIfNotExists(snapInfo, dataStoreRole, snapshot, kvmSnapshotOnlyInPrimaryStorage);
_accountMgr.checkAccess(caller, null, true, snapInfo);
DataStore snapStore = snapInfo.getDataStore();

if (snapStore != null) {
store = snapStore; // pick snapshot image store to create template
}
} else if (skipCopyToSecondary) {
} else if (keepOnPrimary) {
ImageStoreVO imageStore = _imgStoreDao.findOneByZoneAndProtocol(zoneId, "nfs");

Check warning on line 1695 in server/src/main/java/com/cloud/template/TemplateManagerImpl.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/com/cloud/template/TemplateManagerImpl.java#L1695

Added line #L1695 was not covered by tests
if (imageStore == null) {
throw new CloudRuntimeException(String.format("Could not find an NFS secondary storage pool on zone %s to use as a temporary location " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@
import org.apache.logging.log4j.Logger;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -289,4 +291,18 @@ protected Set<Long> getSnapshotIdsOnlyInPrimaryStorage(long volumeId) {

return snapshotIdsOnlyInPrimaryStorage;
}

public void checkIfThereAreMoreThanOnePoolInTheZone(List<Long> poolIds) {
List<Long> poolsInOneZone = new ArrayList<>();

Check warning on line 296 in server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java#L295-L296

Added lines #L295 - L296 were not covered by tests
for (Long poolId : poolIds) {
StoragePoolVO pool = primaryDataStoreDao.findById(poolId);

Check warning on line 298 in server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java#L298

Added line #L298 was not covered by tests
if (pool != null) {
poolsInOneZone.add(pool.getDataCenterId());

Check warning on line 300 in server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java#L300

Added line #L300 was not covered by tests
}
}

Check warning on line 302 in server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java#L302

Added line #L302 was not covered by tests
boolean moreThanOnePoolForZone = poolsInOneZone.stream().filter(itr -> Collections.frequency(poolsInOneZone, itr) > 1).count() > 1;
if (moreThanOnePoolForZone) {
throw new CloudRuntimeException("Cannot copy the snapshot on multiple storage pools in one zone");

Check warning on line 305 in server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java#L305

Added line #L305 was not covered by tests
}
}

Check warning on line 307 in server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java

View check run for this annotation

Codecov / codecov/patch

server/src/main/java/org/apache/cloudstack/snapshot/SnapshotHelper.java#L307

Added line #L307 was not covered by tests
}
2 changes: 2 additions & 0 deletions ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,7 @@
"label.select.source.vcenter.datacenter": "Select the source VMware vCenter Datacenter",
"label.select.tier": "Select Network Tier",
"label.select.zones": "Select zones",
"label.select.storagepools": "Select storage pools",
"label.select.2fa.provider": "Select the provider",
"label.selected.storage": "Selected storage",
"label.self": "Mine",
Expand Down Expand Up @@ -2107,6 +2108,7 @@
"label.storagemotionenabled": "Storage motion enabled",
"label.storagepolicy": "Storage policy",
"label.storagepool": "Storage pool",
"label.storagepools": "Storage pools",
"label.storagepool.tooltip": "Destination Storage Pool. Volume should be located in this Storage Pool",
"label.storagetags": "Storage tags",
"label.storagetype": "Storage type",
Expand Down
47 changes: 46 additions & 1 deletion ui/src/views/storage/FormSchedule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,32 @@
</a-select>
</a-form-item>
</a-col>
<a-col :md="24" :lg="24" v-if="resourceType === 'Volume'">
<a-form-item ref="storageids" name="storageids">
<template #label>
<tooltip-label :title="$t('label.storagepools')" :tooltip="''"/>
</template>
<a-select
id="storagepool-selection"
v-model:value="form.storageids"
mode="multiple"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="storagePoolLoading"
:placeholder="''">
<a-select-option v-for="opt in this.storagePools" :key="opt.id" :label="opt.name || opt.description">
<span>
<resource-icon v-if="opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
<global-outlined v-else style="margin-right: 5px"/>
{{ opt.name || opt.description }}
</span>
</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-divider/>
<div class="tagsTitle">{{ $t('label.tags') }}</div>
Expand Down Expand Up @@ -272,7 +298,8 @@ export default {
timeZoneMap: [],
fetching: false,
listDayOfWeek: ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'],
zones: []
zones: [],
storagePools: []
}
},
created () {
Expand Down Expand Up @@ -307,6 +334,7 @@ export default {
})
if (this.resourceType === 'Volume') {
this.fetchZoneData()
this.fetchStoragePoolData()
}
},
fetchZoneData () {
Expand All @@ -323,6 +351,20 @@ export default {
this.zoneLoading = false
})
},
fetchStoragePoolData () {
const params = {}
params.showicon = true
this.storagePoolsLoading = true
api('listStoragePools', params).then(json => {
const listStoragePools = json.liststoragepoolsresponse.storagepool
if (listStoragePools) {
this.storagePools = listStoragePools
this.storagePools = this.storagePools.filter(pool => pool.storagecapabilities.CAN_COPY_SNAPSHOT_BETWEEN_ZONES && pool.zoneid !== this.resource.zoneid)
}
}).finally(() => {
this.storagePoolsLoading = false
})
},
fetchTimeZone (value) {
this.timeZoneMap = []
this.fetching = true
Expand Down Expand Up @@ -422,6 +464,9 @@ export default {
if (values.zoneids && values.zoneids.length > 0) {
params.zoneids = values.zoneids.join()
}
if (values.storageids && values.storageids.length > 0) {
params.storageids = values.storageids.join()
}
switch (values.intervaltype) {
case 'hourly':
params.schedule = values.time
Expand Down
61 changes: 57 additions & 4 deletions ui/src/views/storage/SnapshotZones.vue
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,39 @@
</a-select-option>
</a-select>
</a-form-item>

<a-form-item ref="storageid" name="storageid" :label="$t('label.storagepools')">
<a-select
id="storage-selection"
mode="multiple"
:placeholder="$t('label.select.storagepools')"
v-model:value="form.storageid"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="storagePoolLoading"
v-focus="true">
<a-select-option v-for="opt in storagePools" :key="opt.id" :label="opt.name || opt.description">
<div>
<span v-if="opt.icon && opt.icon.base64image">
<resource-icon :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
</span>
<global-outlined v-else style="margin-right: 5px" />
{{ opt.name || opt.description }}
</div>
</a-select-option>
</a-select>
</a-form-item>
<div :span="24" class="action-button">
<a-button @click="onCloseModal">{{ $t('label.cancel') }}</a-button>
<a-button type="primary" ref="submit" @click="handleCopySnapshotSubmit">{{ $t('label.ok') }}</a-button>
<a-button
type="primary"
ref="submit"
:disabled="isCopySnapshotSubmitDisabled"
@click="handleCopySnapshotSubmit">
{{ $t('label.ok') }}
</a-button>
</div>
</a-form>
</a-spin>
Expand Down Expand Up @@ -238,6 +267,8 @@ export default {
currentRecord: {},
zones: [],
zoneLoading: false,
storagePools: [],
storagePoolLoading: false,
copyLoading: false,
deleteLoading: false,
showDeleteSnapshot: false,
Expand Down Expand Up @@ -297,12 +328,17 @@ export default {
}
}
},
computed: {
isCopySnapshotSubmitDisabled () {
return this.form.storageid.length === 0 && this.form.zoneid.length === 0
}
},
methods: {
initForm () {
this.formRef = ref()
this.form = reactive({})
this.rules = reactive({
zoneid: [{ type: 'array', required: true, message: this.$t('message.error.select') }]
zoneid: [{ type: 'array', required: false }]
})
},
fetchData () {
Expand Down Expand Up @@ -488,10 +524,26 @@ export default {
this.zoneLoading = false
})
},
fetchStoragePoolData () {
const params = {}
params.showicon = true
this.storagePoolsLoading = true
api('listStoragePools', params).then(json => {
const listStoragePools = json.liststoragepoolsresponse.storagepool
if (listStoragePools) {
this.storagePools = listStoragePools
this.storagePools = this.storagePools.filter(pool => pool.storagecapabilities.CAN_COPY_SNAPSHOT_BETWEEN_ZONES && pool.zoneid !== this.resource.zoneid)
}
}).finally(() => {
this.storagePoolsLoading = false
})
},
showCopySnapshot (record) {
this.currentRecord = record
this.form.zoneid = []
this.form.storageid = []
this.fetchZoneData()
this.fetchStoragePoolData()
this.showCopyActionForm = true
},
onShowDeleteModal (record) {
Expand Down Expand Up @@ -520,7 +572,8 @@ export default {
const params = {
id: this.currentRecord.id,
sourcezoneid: this.currentRecord.zoneid,
destzoneids: values.zoneid.join()
destzoneids: values.zoneid.join(),
storageids: values.storageid.join()
}
this.copyLoading = true
api(this.copyApi, params).then(json => {
Expand Down
Loading

0 comments on commit 0df6764

Please sign in to comment.