Add support to update secondary and primary storage URLs

This commit is contained in:
Pearl Dsilva 2026-05-19 13:15:00 -04:00
parent 522283bdec
commit 3bae3926a1
4 changed files with 42 additions and 5 deletions

View File

@ -50,6 +50,13 @@ public class UpdateImageStoreCmd extends BaseCmd {
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;
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false,
description = "The new URL for the image store (e.g. nfs://new-host/export). " +
"The image store must be in read-only state before its URL can be changed. " +
"After updating, destroy and recreate any Secondary Storage VMs so they remount the new path.",
since = "4.23.0")
private String url;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -70,6 +77,10 @@ public class UpdateImageStoreCmd extends BaseCmd {
return capacityBytes;
}
public String getUrl() {
return url;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -411,7 +411,7 @@ public interface StorageManager extends StorageService {
Long getDiskIopsWriteRate(ServiceOffering offering, DiskOffering diskOffering);
ImageStore updateImageStoreStatus(Long id, String name, Boolean readonly, Long capacityBytes);
ImageStore updateImageStoreStatus(Long id, String name, Boolean readonly, Long capacityBytes, String url);
void cleanupDownloadUrls();

View File

@ -1787,7 +1787,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
&& (_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());
_storageManager.updateImageStoreStatus(storeId, null, null, storageStats.get(storeId).getCapacityBytes(), null);
}
}
// if in _storageStats and not in storageStats it gets discarded

View File

@ -1285,6 +1285,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
changes = true;
}
if (cmd.getUrl() != null) {
changes = true;
}
if (changes) {
StoragePoolVO storagePool = _storagePoolDao.findById(id);
DataStoreProvider dataStoreProvider = _dataStoreProviderMgr.getDataStoreProvider(storagePool.getStorageProviderName());
@ -1300,6 +1304,21 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
_storagePoolDao.updateCapacityIops(id, updatedCapacityIops);
}
if (cmd.getUrl() != null) {
if (!storagePool.isInMaintenance()) {
throw new InvalidParameterValueException("Storage pool must be in Maintenance state before its URL can be changed. " +
"Please put the pool into maintenance first.");
}
URI newUri;
try {
newUri = new URI(cmd.getUrl());
} catch (URISyntaxException e) {
throw new InvalidParameterValueException("Invalid URL format: " + cmd.getUrl());
}
storagePool.setHostAddress(newUri.getHost());
storagePool.setPath(newUri.getPath());
if (newUri.getPort() != -1) {
storagePool.setPort(newUri.getPort());
}
details.put("url", cmd.getUrl());
}
_storagePoolDao.update(id, storagePool);
@ -4129,18 +4148,25 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
@Override
public ImageStore updateImageStore(UpdateImageStoreCmd cmd) {
return updateImageStoreStatus(cmd.getId(), cmd.getName(), cmd.getReadonly(), cmd.getCapacityBytes());
return updateImageStoreStatus(cmd.getId(), cmd.getName(), cmd.getReadonly(), cmd.getCapacityBytes(), cmd.getUrl());
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_UPDATE_IMAGE_STORE_ACCESS_STATE,
eventDescription = "image store access updated")
public ImageStore updateImageStoreStatus(Long id, String name, Boolean readonly, Long capacityBytes) {
public ImageStore updateImageStoreStatus(Long id, String name, Boolean readonly, Long capacityBytes, String url) {
// Input validation
ImageStoreVO imageStoreVO = _imageStoreDao.findById(id);
if (imageStoreVO == null) {
throw new IllegalArgumentException("Unable to find image store with ID: " + id);
}
if (url != null) {
if (!imageStoreVO.isReadonly()) {
throw new InvalidParameterValueException("Image store must be set to read-only (maintenance) state before its URL can be changed. " +
"Please set readOnly=true on the image store first.");
}
imageStoreVO.setUrl(url);
}
if (com.cloud.utils.StringUtils.isNotBlank(name)) {
imageStoreVO.setName(name);
}
@ -4156,7 +4182,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
@Override
public ImageStore updateImageStoreStatus(Long id, Boolean readonly) {
return updateImageStoreStatus(id, null, readonly, null);
return updateImageStoreStatus(id, null, readonly, null, null);
}
/**