You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by sh...@apache.org on 2026/08/18 13:55:54 UTC
(cloudstack) 20/23: Validate URL before obtaining remote size
This is an automated email from the ASF dual-hosted git repository.
shwstppr pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 90f6b2a4cd5cb479dc62f1c5d4c46f9d41e53ebe
Author: Pearl Dsilva <pe...@gmail.com>
AuthorDate: Tue Jul 14 10:24:32 2026 -0400
Validate URL before obtaining remote size
---
.../com/cloud/template/TemplateManagerImpl.java | 15 +-
.../cloud/template/TemplateManagerImplTest.java | 200 +++++++++++++--------
2 files changed, 137 insertions(+), 78 deletions(-)
diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
index 64568c32557..9e2b1120d0e 100755
--- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
@@ -354,6 +354,15 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
return adapter;
}
+ private long validateUrlAndGetSecondaryStorageUsage(TemplateAdapter adapter, String format, String url, boolean isDirectDownload) {
+ boolean isHypervisorTemplateAdapter = adapter instanceof HypervisorTemplateAdapter && !isDirectDownload;
+ if (isHypervisorTemplateAdapter) {
+ UriUtils.validateUrl(format, url, !TemplateManager.getValidateUrlIsResolvableBeforeRegisteringTemplateValue(), isDirectDownload);
+ }
+ return isHypervisorTemplateAdapter ?
+ UriUtils.getRemoteSize(url, StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
+ }
+
@Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "Creating ISO")
public VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws ResourceAllocationException {
@@ -363,8 +372,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
// Secondary storage resource count is not incremented for BareMetalTemplateAdapter
// Note: checking the file size before registering will require the Management Server host to have access to the Internet and a DNS server
// If it does not, UriUtils.getRemoteSize will return 0L.
- long secondaryStorageUsage = adapter instanceof HypervisorTemplateAdapter && !cmd.isDirectDownload() ?
- UriUtils.getRemoteSize(cmd.getUrl(), StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
+ long secondaryStorageUsage = validateUrlAndGetSecondaryStorageUsage(adapter, ImageFormat.ISO.getFileExtension(), cmd.getUrl(), cmd.isDirectDownload());
try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, ResourceType.secondary_storage, null, null, secondaryStorageUsage, reservationDao, _resourceLimitMgr)) {
@@ -403,8 +411,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
- long secondaryStorageUsage = adapter instanceof HypervisorTemplateAdapter && !cmd.isDirectDownload() ?
- UriUtils.getRemoteSize(cmd.getUrl(), StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
+ long secondaryStorageUsage = validateUrlAndGetSecondaryStorageUsage(adapter, cmd.getFormat(), cmd.getUrl(), cmd.isDirectDownload());
try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, ResourceType.secondary_storage, null, null, secondaryStorageUsage, reservationDao, _resourceLimitMgr)) {
diff --git a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
index 808df90349b..af5bdbf9fd1 100755
--- a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
+++ b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
@@ -19,61 +19,28 @@
package com.cloud.template;
-import com.cloud.agent.AgentManager;
-import com.cloud.api.query.dao.SnapshotJoinDao;
-import com.cloud.api.query.dao.UserVmJoinDao;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
-import com.cloud.domain.dao.DomainDao;
-import com.cloud.event.dao.UsageEventDao;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.host.Status;
-import com.cloud.host.dao.HostDao;
-import com.cloud.hypervisor.Hypervisor;
-import com.cloud.hypervisor.HypervisorGuruManager;
-import com.cloud.projects.ProjectManager;
-import com.cloud.resourcelimit.CheckedReservation;
-import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.GuestOSVO;
-import com.cloud.storage.Snapshot;
-import com.cloud.storage.SnapshotVO;
-import com.cloud.storage.Storage;
-import com.cloud.storage.StorageManager;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.StoragePoolStatus;
-import com.cloud.storage.TemplateProfile;
-import com.cloud.storage.VMTemplateStoragePoolVO;
-import com.cloud.storage.VMTemplateStorageResourceAssoc;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.GuestOSDao;
-import com.cloud.storage.dao.LaunchPermissionDao;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.StoragePoolHostDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VMTemplateDetailsDao;
-import com.cloud.storage.dao.VMTemplatePoolDao;
-import com.cloud.storage.dao.VMTemplateZoneDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.AccountVO;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.User;
-import com.cloud.user.UserData;
-import com.cloud.user.UserDataVO;
-import com.cloud.user.UserVO;
-import com.cloud.user.dao.AccountDao;
-import com.cloud.user.dao.UserDataDao;
-import com.cloud.utils.concurrency.NamedThreadFactory;
-import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.dao.VMInstanceDao;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-import junit.framework.TestCase;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
@@ -110,16 +77,15 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.heuristics.HeuristicRuleHelper;
import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.test.utils.SpringUtils;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
@@ -133,26 +99,61 @@ import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
+import com.cloud.agent.AgentManager;
+import com.cloud.api.query.dao.SnapshotJoinDao;
+import com.cloud.api.query.dao.UserVmJoinDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.HypervisorGuruManager;
+import com.cloud.projects.ProjectManager;
+import com.cloud.resourcelimit.CheckedReservation;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.Storage;
+import com.cloud.storage.StorageManager;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.StoragePoolStatus;
+import com.cloud.storage.TemplateProfile;
+import com.cloud.storage.VMTemplateStoragePoolVO;
+import com.cloud.storage.VMTemplateStorageResourceAssoc;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.storage.dao.LaunchPermissionDao;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplateDetailsDao;
+import com.cloud.storage.dao.VMTemplatePoolDao;
+import com.cloud.storage.dao.VMTemplateZoneDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.User;
+import com.cloud.user.UserData;
+import com.cloud.user.UserDataVO;
+import com.cloud.user.UserVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDataDao;
+import com.cloud.utils.UriUtils;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import junit.framework.TestCase;
@RunWith(MockitoJUnitRunner.class)
public class TemplateManagerImplTest extends TestCase {
@@ -637,6 +638,57 @@ public class TemplateManagerImplTest extends TestCase {
Mockito.verify(dataStoreManager, Mockito.times(0)).getImageStoreWithFreeCapacity(Mockito.anyLong());
}
+ private HypervisorTemplateAdapter mockHypervisorTemplateAdapter() {
+ HypervisorTemplateAdapter adapter = Mockito.mock(HypervisorTemplateAdapter.class);
+ when(adapter.getName()).thenReturn(TemplateAdapter.TemplateAdapterType.Hypervisor.getName());
+ templateManager.setTemplateAdapters(new ArrayList<>(List.of(adapter)));
+ return adapter;
+ }
+
+ @Test
+ public void testRegisterTemplateValidatesUrlBeforeProbingSize() {
+ RegisterTemplateCmd cmd = Mockito.mock(RegisterTemplateCmd.class);
+ when(cmd.getTemplateTag()).thenReturn(null);
+ when(cmd.isRoutingType()).thenReturn(null);
+ when(cmd.getUrl()).thenReturn("http://10.0.0.5/template.qcow2");
+ when(cmd.getFormat()).thenReturn("QCOW2");
+ when(cmd.getHypervisor()).thenReturn(Hypervisor.HypervisorType.KVM.toString());
+ when(cmd.isDirectDownload()).thenReturn(false);
+ when(cmd.getEntityOwnerId()).thenReturn(1L);
+ when(_accountMgr.getAccount(1L)).thenReturn(Mockito.mock(Account.class));
+
+ mockHypervisorTemplateAdapter();
+
+ try (MockedStatic<UriUtils> uriUtilsMock = Mockito.mockStatic(UriUtils.class)) {
+ uriUtilsMock.when(() -> UriUtils.validateUrl(any(), any(), Mockito.anyBoolean(), Mockito.anyBoolean()))
+ .thenThrow(new IllegalArgumentException("Illegal host specified in URL."));
+
+ Assert.assertThrows(IllegalArgumentException.class, () -> templateManager.registerTemplate(cmd));
+
+ uriUtilsMock.verify(() -> UriUtils.getRemoteSize(any(), any()), Mockito.never());
+ }
+ }
+
+ @Test
+ public void testRegisterIsoValidatesUrlBeforeProbingSize() throws Exception {
+ RegisterIsoCmd cmd = Mockito.mock(RegisterIsoCmd.class);
+ when(cmd.getUrl()).thenReturn("http://10.0.0.5/image.iso");
+ when(cmd.isDirectDownload()).thenReturn(false);
+ when(cmd.getEntityOwnerId()).thenReturn(1L);
+ when(_accountMgr.getAccount(1L)).thenReturn(Mockito.mock(Account.class));
+
+ mockHypervisorTemplateAdapter();
+
+ try (MockedStatic<UriUtils> uriUtilsMock = Mockito.mockStatic(UriUtils.class)) {
+ uriUtilsMock.when(() -> UriUtils.validateUrl(any(), any(), Mockito.anyBoolean(), Mockito.anyBoolean()))
+ .thenThrow(new IllegalArgumentException("Illegal host specified in URL."));
+
+ Assert.assertThrows(IllegalArgumentException.class, () -> templateManager.registerIso(cmd));
+
+ uriUtilsMock.verify(() -> UriUtils.getRemoteSize(any(), any()), Mockito.never());
+ }
+ }
+
@Test
public void testRegisterTemplateWithTemplateType() {
RegisterTemplateCmd cmd = Mockito.mock(RegisterTemplateCmd.class);