This is an automated email from the ASF dual-hosted git repository.

Pearl1594 pushed a commit to branch support-update-pri-sec-stg-url
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 3bae3926a150448a91f7600ade1c774d6010e085
Author: Pearl Dsilva <[email protected]>
AuthorDate: Tue May 19 13:15:00 2026 -0400

    Add support to update secondary and primary storage URLs
---
 .../command/admin/storage/UpdateImageStoreCmd.java | 11 ++++++++
 .../java/com/cloud/storage/StorageManager.java     |  2 +-
 .../main/java/com/cloud/server/StatsCollector.java |  2 +-
 .../java/com/cloud/storage/StorageManagerImpl.java | 32 ++++++++++++++++++++--
 4 files changed, 42 insertions(+), 5 deletions(-)

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 0e1631a46ba..ee83b78d07f 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
@@ -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///////////////////
     /////////////////////////////////////////////////////
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 3c62738f9ed..455ac8c3338 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
@@ -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();
 
diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java 
b/server/src/main/java/com/cloud/server/StatsCollector.java
index 049ed454361..5a98feac51a 100644
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@ -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
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java 
b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index 7c501c78bee..f62df0585ae 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -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);
     }
 
     /**

Reply via email to