Extra parameter for UpdateImageStore (#8941)
* Extra parameter for UpdateImageStore
* add name parameter
* ui
* cleanup
* update DB from storage stats results
diff --git a/api/src/main/java/com/cloud/storage/StorageService.java b/api/src/main/java/com/cloud/storage/StorageService.java
index bb086ad..d11246b 100644
--- a/api/src/main/java/com/cloud/storage/StorageService.java
+++ b/api/src/main/java/com/cloud/storage/StorageService.java
@@ -27,6 +27,7 @@
import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd;
+import org.apache.cloudstack.api.command.admin.storage.UpdateImageStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
import com.cloud.exception.DiscoveryException;
@@ -103,6 +104,8 @@
*/
ImageStore migrateToObjectStore(String name, String url, String providerName, Map<String, String> details) throws DiscoveryException;
+ ImageStore updateImageStore(UpdateImageStoreCmd cmd);
+
ImageStore updateImageStoreStatus(Long id, Boolean readonly);
void updateStorageCapabilities(Long poolId, boolean failOnChecks);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateImageStoreCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateImageStoreCmd.java
index d7dca93..87d056c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateImageStoreCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateImageStoreCmd.java
@@ -41,10 +41,17 @@
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ImageStoreResponse.class, required = true, description = "Image Store UUID")
private Long id;
- @Parameter(name = ApiConstants.READ_ONLY, type = CommandType.BOOLEAN, required = true, description = "If set to true, it designates the corresponding image store to read-only, " +
- "hence not considering them during storage migration")
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = false, description = "The new name for the Image Store.")
+ private String name;
+
+ @Parameter(name = ApiConstants.READ_ONLY, type = CommandType.BOOLEAN, required = false,
+ description = "If set to true, it designates the corresponding image store to read-only, hence not considering them during storage migration")
private Boolean readonly;
+ @Parameter(name = ApiConstants.CAPACITY_BYTES, type = CommandType.LONG, required = false,
+ description = "The number of bytes CloudStack can use on this image storage.\n\tNOTE: this will be overwritten by the StatsCollector as soon as there is a SSVM to query the storage.")
+ private Long capacityBytes;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -53,17 +60,25 @@
return id;
}
+ public String getName() {
+ return name;
+ }
+
public Boolean getReadonly() {
return readonly;
}
+ public Long getCapacityBytes() {
+ return capacityBytes;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
- ImageStore result = _storageService.updateImageStoreStatus(getId(), getReadonly());
+ ImageStore result = _storageService.updateImageStore(this);
ImageStoreResponse storeResponse = null;
if (result != null) {
storeResponse = _responseGenerator.createImageStoreResponse(result);
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ImageStoreResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ImageStoreResponse.java
index 532963d..ee44b6b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/ImageStoreResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/ImageStoreResponse.java
@@ -27,11 +27,11 @@
@EntityReference(value = ImageStore.class)
public class ImageStoreResponse extends BaseResponseWithAnnotations {
- @SerializedName("id")
+ @SerializedName(ApiConstants.ID)
@Param(description = "the ID of the image store")
private String id;
- @SerializedName("zoneid")
+ @SerializedName(ApiConstants.ZONE_ID)
@Param(description = "the Zone ID of the image store")
private String zoneId;
@@ -39,15 +39,15 @@
@Param(description = "the Zone name of the image store")
private String zoneName;
- @SerializedName("name")
+ @SerializedName(ApiConstants.NAME)
@Param(description = "the name of the image store")
private String name;
- @SerializedName("url")
+ @SerializedName(ApiConstants.URL)
@Param(description = "the url of the image store")
private String url;
- @SerializedName("protocol")
+ @SerializedName(ApiConstants.PROTOCOL)
@Param(description = "the protocol of the image store")
private String protocol;
@@ -55,11 +55,11 @@
@Param(description = "the provider name of the image store")
private String providerName;
- @SerializedName("scope")
+ @SerializedName(ApiConstants.SCOPE)
@Param(description = "the scope of the image store")
private ScopeType scope;
- @SerializedName("readonly")
+ @SerializedName(ApiConstants.READ_ONLY)
@Param(description = "defines if store is read-only")
private Boolean readonly;
diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index 7fdec90..411a6ca 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -350,6 +350,8 @@
Long getDiskIopsWriteRate(ServiceOffering offering, DiskOffering diskOffering);
+ ImageStore updateImageStoreStatus(Long id, String name, Boolean readonly, Long capacityBytes);
+
void cleanupDownloadUrls();
void setDiskProfileThrottling(DiskProfile dskCh, ServiceOffering offering, DiskOffering diskOffering);
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index 51aed5a..2dea6f8 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -2739,7 +2739,7 @@
@Override
public ListResponse<ImageStoreResponse> searchForImageStores(ListImageStoresCmd cmd) {
Pair<List<ImageStoreJoinVO>, Integer> result = searchForImageStoresInternal(cmd);
- ListResponse<ImageStoreResponse> response = new ListResponse<ImageStoreResponse>();
+ ListResponse<ImageStoreResponse> response = new ListResponse<>();
List<ImageStoreResponse> poolResponses = ViewResponseHelper.createImageStoreResponse(result.first().toArray(new ImageStoreJoinVO[result.first().size()]));
response.setResponses(poolResponses, result.second());
diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java b/server/src/main/java/com/cloud/server/StatsCollector.java
index 1982009..e44c094 100644
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@ -1671,7 +1671,7 @@
}
List<DataStore> stores = _dataStoreMgr.listImageStores();
- ConcurrentHashMap<Long, StorageStats> storageStats = new ConcurrentHashMap<Long, StorageStats>();
+ ConcurrentHashMap<Long, StorageStats> storageStats = new ConcurrentHashMap<>();
for (DataStore store : stores) {
if (store.getUri() == null) {
continue;
@@ -1691,7 +1691,7 @@
LOGGER.trace("HostId: " + storeId + " Used: " + toHumanReadableSize(((StorageStats)answer).getByteUsed()) + " Total Available: " + toHumanReadableSize(((StorageStats)answer).getCapacityBytes()));
}
}
- _storageStats = storageStats;
+ updateStorageStats(storageStats);
ConcurrentHashMap<Long, StorageStats> storagePoolStats = new ConcurrentHashMap<Long, StorageStats>();
List<StoragePoolVO> storagePools = _storagePoolDao.listAll();
@@ -1737,6 +1737,19 @@
LOGGER.error("Error trying to retrieve storage stats", t);
}
}
+
+ private void updateStorageStats(ConcurrentHashMap<Long, StorageStats> storageStats) {
+ for (Long storeId : storageStats.keySet()) {
+ if (_storageStats.containsKey(storeId)
+ && (_storageStats.get(storeId).getCapacityBytes() == 0l
+ || _storageStats.get(storeId).getCapacityBytes() != storageStats.get(storeId).getCapacityBytes())) {
+ // get add to DB rigorously
+ _storageManager.updateImageStoreStatus(storeId, null, null, storageStats.get(storeId).getCapacityBytes());
+ }
+ }
+ // if in _storageStats and not in storageStats it gets discarded
+ _storageStats = storageStats;
+ }
}
class AutoScaleMonitor extends ManagedContextRunnable {
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index c6379a7..290c692 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -57,6 +57,7 @@
import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd;
+import org.apache.cloudstack.api.command.admin.storage.UpdateImageStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
@@ -116,7 +117,6 @@
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -212,6 +212,7 @@
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.UriUtils;
+import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
@@ -2998,17 +2999,35 @@
}
@Override
- public ImageStore updateImageStoreStatus(Long id, Boolean readonly) {
+ public ImageStore updateImageStore(UpdateImageStoreCmd cmd) {
+ return updateImageStoreStatus(cmd.getId(), cmd.getName(), cmd.getReadonly(), cmd.getCapacityBytes());
+ }
+
+ @Override
+ public ImageStore updateImageStoreStatus(Long id, String name, Boolean readonly, Long capacityBytes) {
// Input validation
ImageStoreVO imageStoreVO = _imageStoreDao.findById(id);
if (imageStoreVO == null) {
throw new IllegalArgumentException("Unable to find image store with ID: " + id);
}
- imageStoreVO.setReadonly(readonly);
+ if (com.cloud.utils.StringUtils.isNotBlank(name)) {
+ imageStoreVO.setName(name);
+ }
+ if (capacityBytes != null) {
+ imageStoreVO.setTotalSize(capacityBytes);
+ }
+ if (readonly != null) {
+ imageStoreVO.setReadonly(readonly);
+ }
_imageStoreDao.update(id, imageStoreVO);
return imageStoreVO;
}
+ @Override
+ public ImageStore updateImageStoreStatus(Long id, Boolean readonly) {
+ return updateImageStoreStatus(id, null, readonly, null);
+ }
+
/**
* @param poolId - Storage pool id for pool to update.
* @param failOnChecks - If true, throw an error if pool type and state checks fail.
diff --git a/ui/src/config/section/infra/secondaryStorages.js b/ui/src/config/section/infra/secondaryStorages.js
index 93c54dc..793aa02 100644
--- a/ui/src/config/section/infra/secondaryStorages.js
+++ b/ui/src/config/section/infra/secondaryStorages.js
@@ -77,21 +77,10 @@
},
{
api: 'updateImageStore',
- icon: 'stop-outlined',
- label: 'label.action.image.store.read.only',
- message: 'message.action.secondary.storage.read.only',
+ icon: 'edit-outlined',
+ label: 'label.edit',
dataView: true,
- defaultArgs: { readonly: true },
- show: (record) => { return record.readonly === false }
- },
- {
- api: 'updateImageStore',
- icon: 'check-circle-outlined',
- label: 'label.action.image.store.read.write',
- message: 'message.action.secondary.storage.read.write',
- dataView: true,
- defaultArgs: { readonly: false },
- show: (record) => { return record.readonly === true }
+ args: ['name', 'readonly', 'capacitybytes']
},
{
api: 'deleteImageStore',
diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue
index acb6fd6..6cf0543 100644
--- a/ui/src/views/AutogenView.vue
+++ b/ui/src/views/AutogenView.vue
@@ -679,7 +679,6 @@
},
getOkProps () {
if (this.selectedRowKeys.length > 0 && this.currentAction?.groupAction) {
- return { props: { type: 'default' } }
} else {
return { props: { type: 'primary' } }
}