You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by su...@apache.org on 2026/01/22 07:53:48 UTC
(cloudstack) branch 4.22 updated (036489b288c -> b1f870ae833)
This is an automated email from the ASF dual-hosted git repository.
sureshanaparti pushed a change to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
from 036489b288c CKS: fix resource limitation check on cpu when scale cks cluster (#12379)
add a4b1a27c7d2 ui: fix 404 on login after forgot password (#12448)
add 42f1e19362a Mask vncPasswd being logged in agent.log (#12404)
add 2a6ce0c8a81 Adds url kubernetes iso (#10862)
add 03d24ff851d Fix NPE on primary storage delete (#11817)
add da518e90362 CKS: Add image store validation for Kubernetes version registration (#12418)
add cf36fb00008 Set nfsVersion in ssvm agent.properties only if it is not null (#12445)
add 496bc0329cd Fix: Condition for aborting migration, resume paused VMs on destination (#12331)
add 8db7cab7ba4 Storage pool monitor disconnect improvements (#12398)
new b1f870ae833 Merge branch '4.20' into 4.22
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../org/apache/cloudstack/api/ApiConstants.java | 1 +
.../wrapper/LibvirtMigrateCommandWrapper.java | 70 ++++++++++-----
.../wrapper/LibvirtStartCommandWrapper.java | 5 +-
.../wrapper/LibvirtMigrateCommandWrapperTest.java | 26 +++++-
.../version/KubernetesVersionManagerImpl.java | 52 ++++++++++--
.../KubernetesSupportedVersionResponse.java | 12 +++
.../version/KubernetesVersionManagerImplTest.java | 78 ++++++++++++++++-
.../version/KubernetesVersionServiceTest.java | 99 +++++++++++++++++-----
.../java/com/cloud/storage/StorageManagerImpl.java | 8 +-
.../cloud/storage/listener/StoragePoolMonitor.java | 28 ++++--
.../SecondaryStorageManagerImpl.java | 6 +-
ui/public/locales/en.json | 1 +
ui/public/locales/pt_BR.json | 1 +
ui/src/config/section/image.js | 6 +-
ui/src/views/auth/ForgotPassword.vue | 2 +-
15 files changed, 329 insertions(+), 66 deletions(-)
(cloudstack) 01/01: Merge branch '4.20' into 4.22
Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sureshanaparti pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit b1f870ae833ed6a6bf32db622a2d0b5d2c8360a1
Merge: 036489b288c 8db7cab7ba4
Author: Suresh Kumar Anaparti <su...@gmail.com>
AuthorDate: Thu Jan 22 13:23:21 2026 +0530
Merge branch '4.20' into 4.22
.../org/apache/cloudstack/api/ApiConstants.java | 1 +
.../wrapper/LibvirtMigrateCommandWrapper.java | 70 ++++++++++-----
.../wrapper/LibvirtStartCommandWrapper.java | 5 +-
.../wrapper/LibvirtMigrateCommandWrapperTest.java | 26 +++++-
.../version/KubernetesVersionManagerImpl.java | 52 ++++++++++--
.../KubernetesSupportedVersionResponse.java | 12 +++
.../version/KubernetesVersionManagerImplTest.java | 78 ++++++++++++++++-
.../version/KubernetesVersionServiceTest.java | 99 +++++++++++++++++-----
.../java/com/cloud/storage/StorageManagerImpl.java | 8 +-
.../cloud/storage/listener/StoragePoolMonitor.java | 28 ++++--
.../SecondaryStorageManagerImpl.java | 6 +-
ui/public/locales/en.json | 1 +
ui/public/locales/pt_BR.json | 1 +
ui/src/config/section/image.js | 6 +-
ui/src/views/auth/ForgotPassword.vue | 2 +-
15 files changed, 329 insertions(+), 66 deletions(-)
diff --cc plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java
index 81328d6ffb9,fe18a88fe1f..43607edc53a
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java
@@@ -287,15 -273,12 +288,15 @@@ public final class LibvirtMigrateComman
} catch (final LibvirtException e) {
logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage());
}
- if (state != null && state == DomainState.VIR_DOMAIN_RUNNING) {
+ if (state != null && (state == DomainState.VIR_DOMAIN_RUNNING || state == DomainState.VIR_DOMAIN_PAUSED)) {
try {
DomainJobInfo job = dm.getJobInfo();
- logger.info(String.format("Aborting migration of VM [%s] with domain job [%s] due to time out after %d seconds.", vmName, job, migrateWait));
+ logger.warn("Aborting migration of VM {} with domain job [{}] due to timeout after {} seconds. " +
+ "Job stats: data processed={} bytes, data remaining={} bytes", vmName, job, migrateWait, job.getDataProcessed(), job.getDataRemaining());
dm.abortJob();
result = String.format("Migration of VM [%s] was cancelled by CloudStack due to time out after %d seconds.", vmName, migrateWait);
+ commandState = Command.State.FAILED;
+ libvirtComputingResource.createOrUpdateLogFileForCommand(command, commandState);
logger.debug(result);
break;
} catch (final LibvirtException e) {
diff --cc plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java
index 0407ed8bbfd,05d89cc3d97..aa36fb89765
--- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java
+++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java
@@@ -1089,153 -1020,27 +1089,177 @@@ public class LibvirtMigrateCommandWrapp
Assert.assertTrue(finalXml.contains(newIsoVolumePath));
}
+ @Test
+ public void testMaskVncPwdDomain() {
+ // Test case 1: Single quotes
+ String xml1 = "<graphics type='vnc' port='5900' passwd='secret123'/>";
+ String expected1 = "<graphics type='vnc' port='5900' passwd='*****'/>";
+ assertEquals(expected1, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml1));
+
+ // Test case 2: Double quotes
+ String xml2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"mypassword\"/>";
+ String expected2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"*****\"/>";
+ assertEquals(expected2, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml2));
+
+ // Test case 3: Non-VNC graphics (should remain unchanged)
+ String xml3 = "<graphics type='spice' port='5902' passwd='notvnc'/>";
+ assertEquals(xml3, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml3));
+
+ // Test case 4: Multiple VNC entries in one string
+ String xml4 = "<graphics type='vnc' port='5900' passwd='a'/>\n" +
+ "<graphics type='vnc' port='5901' passwd='b'/>";
+ String expected4 = "<graphics type='vnc' port='5900' passwd='*****'/>\n" +
+ "<graphics type='vnc' port='5901' passwd='*****'/>";
+ assertEquals(expected4, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml4));
+ }
++
+ @Test
+ public void updateGpuDevicesIfNeededTestNoGpuDevice() throws Exception {
+ Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
+ Mockito.doReturn(null).when(virtualMachineTOMock).getGpuDevice();
+
+ String result = libvirtMigrateCmdWrapper.updateGpuDevicesIfNeeded(migrateCommandMock, xmlWithoutGpuDevices, libvirtComputingResourceMock);
+
+ Assert.assertEquals("XML should remain unchanged when no GPU device is present", xmlWithoutGpuDevices, result);
+ }
+
+ @Test
+ public void updateGpuDevicesIfNeededTestNoDevicesSection() throws Exception {
+ List<VgpuTypesInfo> gpuDevices = createTestMixedGpuDevices();
+ GPUDeviceTO gpuDeviceTO = Mockito.mock(GPUDeviceTO.class);
+ Mockito.doReturn(gpuDevices).when(gpuDeviceTO).getGpuDevices();
+
+ Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
+ Mockito.doReturn(gpuDeviceTO).when(virtualMachineTOMock).getGpuDevice();
+
+ String result = libvirtMigrateCmdWrapper.updateGpuDevicesIfNeeded(migrateCommandMock, xmlNoDevicesSection, libvirtComputingResourceMock);
+
+ Assert.assertEquals("XML should remain unchanged when no devices section is found", xmlNoDevicesSection, result);
+ }
+
+ @Test
+ public void updateGpuDevicesIfNeededTestWithPciDevice() throws Exception {
+ List<VgpuTypesInfo> gpuDevices = createTestPciGpuDevice();
+ GPUDeviceTO gpuDeviceTO = Mockito.mock(GPUDeviceTO.class);
+ Mockito.doReturn(gpuDevices).when(gpuDeviceTO).getGpuDevices();
+
+ Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
+ Mockito.doReturn(gpuDeviceTO).when(virtualMachineTOMock).getGpuDevice();
+
+ String result = libvirtMigrateCmdWrapper.updateGpuDevicesIfNeeded(migrateCommandMock, xmlWithGpuDevices, libvirtComputingResourceMock);
+
+ // Verify that old GPU devices are removed and new ones are added
+ Assert.assertFalse("Old PCI device should be removed", result.contains("bus='0x01' slot='0x00'"));
+ Assert.assertFalse("Old MDEV device should be removed", result.contains("4b20d080-1b54-4048-85b3-a6a62d165c01"));
+ Assert.assertTrue("New PCI device should be added", result.contains("bus=\"0x02\""));
+ Assert.assertTrue("New PCI device should be added", result.contains("slot=\"0x00\""));
+ Assert.assertTrue("PCI device should have vfio driver", result.contains("name=\"vfio\""));
+ }
+
+ @Test
+ public void updateGpuDevicesIfNeededTestWithMdevDevice() throws Exception {
+ List<VgpuTypesInfo> gpuDevices = createTestMdevGpuDevice();
+ GPUDeviceTO gpuDeviceTO = Mockito.mock(GPUDeviceTO.class);
+ Mockito.doReturn(gpuDevices).when(gpuDeviceTO).getGpuDevices();
+
+ Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
+ Mockito.doReturn(gpuDeviceTO).when(virtualMachineTOMock).getGpuDevice();
+
+ String result = libvirtMigrateCmdWrapper.updateGpuDevicesIfNeeded(migrateCommandMock, xmlWithGpuDevices, libvirtComputingResourceMock);
+
+ // Verify that old GPU devices are removed and new ones are added
+ Assert.assertFalse("Old PCI device should be removed", result.contains("bus='0x01' slot='0x00'"));
+ Assert.assertFalse("Old MDEV device should be removed", result.contains("4b20d080-1b54-4048-85b3-a6a62d165c01"));
+ Assert.assertTrue("New MDEV device should be added", result.contains("6f20d080-1b54-4048-85b3-a6a62d165c01"));
+ Assert.assertTrue("MDEV device should have display=off", result.contains("display=\"off\""));
+ }
+
+ @Test
+ public void updateGpuDevicesIfNeededTestWithMixedDevices() throws Exception {
+ List<VgpuTypesInfo> gpuDevices = createTestMixedGpuDevices();
+ GPUDeviceTO gpuDeviceTO = Mockito.mock(GPUDeviceTO.class);
+ Mockito.doReturn(gpuDevices).when(gpuDeviceTO).getGpuDevices();
+
+ Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
+ Mockito.doReturn(gpuDeviceTO).when(virtualMachineTOMock).getGpuDevice();
+
+ String result = libvirtMigrateCmdWrapper.updateGpuDevicesIfNeeded(migrateCommandMock, xmlWithGpuDevices, libvirtComputingResourceMock);
+
+ // Verify both PCI and MDEV devices are added
+ Assert.assertTrue("PCI device should be added", result.contains("bus=\"0x02\""));
+ Assert.assertTrue("PCI device should be added", result.contains("slot=\"0x00\""));
+ Assert.assertTrue("MDEV device should be added", result.contains("6f20d080-1b54-4048-85b3-a6a62d165c01"));
+
+ // Count hostdev elements to ensure we have both
+ long hostdevCount = result.lines().filter(line -> line.contains("<hostdev")).count();
+ Assert.assertEquals("Should have 2 hostdev elements", 2, hostdevCount);
+ }
+
+ @Test
+ public void updateGpuDevicesIfNeededTestRemoveAllGpuDevices() throws Exception {
+ List<VgpuTypesInfo> gpuDevices = new ArrayList<>(); // Empty list
+ GPUDeviceTO gpuDeviceTO = Mockito.mock(GPUDeviceTO.class);
+ Mockito.doReturn(gpuDevices).when(gpuDeviceTO).getGpuDevices();
+
+ Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
+ Mockito.doReturn(gpuDeviceTO).when(virtualMachineTOMock).getGpuDevice();
+
+ String result = libvirtMigrateCmdWrapper.updateGpuDevicesIfNeeded(migrateCommandMock, xmlWithoutGpuDevices, libvirtComputingResourceMock);
+
+ // Verify all GPU devices are removed
+ Assert.assertFalse("Old PCI device should be removed", result.contains("bus=\"0x01\""));
+ Assert.assertFalse("Old PCI device should be removed", result.contains("slot=\"0x00\""));
+ Assert.assertFalse("Old MDEV device should be removed", result.contains("4b20d080-1b54-4048-85b3-a6a62d165c01"));
+
+ // Verify no hostdev elements remain
+ long hostdevCount = result.lines().filter(line -> line.contains("<hostdev")).count();
+ Assert.assertEquals("Should have no hostdev elements", 0, hostdevCount);
+ }
+
+ // Helper methods for creating test GPU devices
+ private List<VgpuTypesInfo> createTestPciGpuDevice() {
+ List<VgpuTypesInfo> devices = new ArrayList<>();
+ VgpuTypesInfo pciDevice = new VgpuTypesInfo(
+ GpuDevice.DeviceType.PCI,
+ "NVIDIA Corporation Tesla T4",
+ "passthrough",
+ "02:00.0", // New bus address for destination host
+ "10de",
+ "NVIDIA Corporation",
+ "1eb8",
+ "Tesla T4"
+ );
+ pciDevice.setDisplay(false);
+ devices.add(pciDevice);
+ return devices;
+ }
+
+ private List<VgpuTypesInfo> createTestMdevGpuDevice() {
+ List<VgpuTypesInfo> devices = new ArrayList<>();
+ VgpuTypesInfo mdevDevice = new VgpuTypesInfo(
+ GpuDevice.DeviceType.MDEV,
+ "nvidia-63",
+ "GRID T4-2Q",
+ "6f20d080-1b54-4048-85b3-a6a62d165c01", // New UUID for destination host
+ "10de",
+ "NVIDIA Corporation",
+ "1eb8",
+ "Tesla T4"
+ );
+ mdevDevice.setDisplay(false);
+ devices.add(mdevDevice);
+ return devices;
+ }
+
+ private List<VgpuTypesInfo> createTestMixedGpuDevices() {
+ List<VgpuTypesInfo> devices = new ArrayList<>();
+
+ // Add PCI device
+ devices.addAll(createTestPciGpuDevice());
+
+ // Add MDEV device
+ devices.addAll(createTestMdevGpuDevice());
+
+ return devices;
+ }
}
diff --cc plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java
index 99f826402ce,8363f6f87e3..aef020335f2
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java
@@@ -347,8 -328,49 +359,34 @@@ public class KubernetesVersionManagerIm
return createKubernetesSupportedVersionListResponse(versions, versionsAndCount.second());
}
+ private void validateImageStoreForZone(Long zoneId, boolean directDownload) {
+ if (directDownload) {
+ return;
+ }
+ if (zoneId != null) {
+ List<ImageStoreVO> imageStores = imageStoreDao.listStoresByZoneId(zoneId);
+ if (CollectionUtils.isEmpty(imageStores)) {
+ DataCenterVO zone = dataCenterDao.findById(zoneId);
+ String zoneName = zone != null ? zone.getName() : String.valueOf(zoneId);
+ throw new InvalidParameterValueException(String.format("Unable to register Kubernetes version ISO. No image store available in zone: %s", zoneName));
+ }
+ } else {
+ List<DataCenterVO> zones = dataCenterDao.listAllZones();
+ List<String> zonesWithoutStorage = new ArrayList<>();
+ for (DataCenterVO zone : zones) {
+ List<ImageStoreVO> imageStores = imageStoreDao.listStoresByZoneId(zone.getId());
+ if (CollectionUtils.isEmpty(imageStores)) {
+ zonesWithoutStorage.add(zone.getName());
+ }
+ }
+ if (!zonesWithoutStorage.isEmpty()) {
+ throw new InvalidParameterValueException(String.format("Unable to register Kubernetes version ISO for all zones. The following zones have no image store: %s", String.join(", ", zonesWithoutStorage)));
+ }
+ }
+ }
+
- @Override
- @ActionEvent(eventType = KubernetesVersionEventTypes.EVENT_KUBERNETES_VERSION_ADD,
- eventDescription = "Adding Kubernetes supported version")
- public KubernetesSupportedVersionResponse addKubernetesSupportedVersion(final AddKubernetesSupportedVersionCmd cmd) {
- if (!KubernetesClusterService.KubernetesServiceEnabled.value()) {
- throw new CloudRuntimeException("Kubernetes Service plugin is disabled");
- }
- String name = cmd.getName();
- final String semanticVersion = cmd.getSemanticVersion();
- final Long zoneId = cmd.getZoneId();
- final String isoUrl = cmd.getUrl();
- final String isoChecksum = cmd.getChecksum();
- final Integer minimumCpu = cmd.getMinimumCpu();
- final Integer minimumRamSize = cmd.getMinimumRamSize();
- final boolean isDirectDownload = cmd.isDirectDownload();
- CPU.CPUArch arch = cmd.getArch();
-
+ private void validateKubernetesSupportedVersion(Long zoneId, String semanticVersion, Integer minimumCpu,
+ Integer minimumRamSize, boolean isDirectDownload) {
if (minimumCpu == null || minimumCpu < KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU) {
throw new InvalidParameterValueException(String.format("Invalid value for %s parameter. Minimum %d vCPUs required.", ApiConstants.MIN_CPU_NUMBER, KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU));
}
@@@ -411,33 -414,9 +451,33 @@@
supportedVersionVO = kubernetesSupportedVersionDao.persist(supportedVersionVO);
CallContext.current().putContextParameter(KubernetesSupportedVersion.class, supportedVersionVO.getUuid());
- return createKubernetesSupportedVersionResponse(supportedVersionVO);
+ return createKubernetesSupportedVersionResponse(supportedVersionVO, true);
}
+ @Override
+ public GetUploadParamsResponse registerKubernetesSupportedVersionForPostUpload(GetUploadParamsForKubernetesSupportedVersionCmd cmd) {
+ if (!KubernetesClusterService.KubernetesServiceEnabled.value()) {
+ throw new CloudRuntimeException("Kubernetes Service plugin is disabled");
+ }
+ String name = cmd.getName();
+ final String semanticVersion = cmd.getSemanticVersion();
+ final Long zoneId = cmd.getZoneId();
+ final String isoChecksum = cmd.getChecksum();
+ final Integer minimumCpu = cmd.getMinimumCpu();
+ final Integer minimumRamSize = cmd.getMinimumRamSize();
+
+ validateKubernetesSupportedVersion(zoneId, semanticVersion, minimumCpu, minimumRamSize, false);
+
+ GetUploadParamsResponse response = registerKubernetesVersionIsoForUpload(zoneId, name, isoChecksum);
+
+ VMTemplateVO template = templateDao.findByUuid(response.getId().toString());
+ KubernetesSupportedVersionVO supportedVersionVO = new KubernetesSupportedVersionVO(name, semanticVersion, template.getId(), zoneId, minimumCpu, minimumRamSize);
+ supportedVersionVO = kubernetesSupportedVersionDao.persist(supportedVersionVO);
+ CallContext.current().putContextParameter(KubernetesSupportedVersion.class, supportedVersionVO.getUuid());
+
+ return response;
+ }
+
@Override
@ActionEvent(eventType = KubernetesVersionEventTypes.EVENT_KUBERNETES_VERSION_DELETE,
eventDescription = "deleting Kubernetes supported version", async = true)
diff --cc server/src/main/java/com/cloud/storage/listener/StoragePoolMonitor.java
index b432858f2e0,6df3cbaeedf..2f9750edee2
--- a/server/src/main/java/com/cloud/storage/listener/StoragePoolMonitor.java
+++ b/server/src/main/java/com/cloud/storage/listener/StoragePoolMonitor.java
@@@ -21,12 -20,8 +21,13 @@@ import java.util.List
import javax.inject.Inject;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.exception.StorageConflictException;
import com.cloud.storage.StorageManager;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+ import com.cloud.utils.Profiler;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
diff --cc services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
index 2ee1dcb37da,c9bcb911000..e26091f677e
--- a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
+++ b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
@@@ -1229,22 -1224,11 +1229,24 @@@ public class SecondaryStorageManagerImp
if (dc.getDns2() != null) {
buf.append(" dns2=").append(dc.getDns2());
}
- String nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStores.get(0).getId()) : null;
- buf.append(" nfsVersion=").append(nfsVersion);
+ String nfsVersion = imageStoreDetailsUtil.getNfsVersion(secStores.get(0).getId());
+ if (StringUtils.isNotBlank(nfsVersion)) {
+ buf.append(" nfsVersion=").append(nfsVersion);
+ }
buf.append(" keystore_password=").append(VirtualMachineGuru.getEncodedString(PasswordGenerator.generateRandomPassword(16)));
+
+ if (SystemVmEnableUserData.valueIn(dc.getId())) {
+ String userDataUuid = SecondaryStorageVmUserData.valueIn(dc.getId());
+ try {
+ String userData = userDataManager.validateAndGetUserDataForSystemVM(userDataUuid);
+ if (StringUtils.isNotBlank(userData)) {
+ buf.append(" userdata=").append(userData);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed to load user data for the ssvm, ignored", e);
+ }
+ }
+
String bootArgs = buf.toString();
if (logger.isDebugEnabled()) {
logger.debug(String.format("Boot args for machine profile [%s]: [%s].", profile.toString(), bootArgs));
diff --cc ui/src/config/section/image.js
index 7172049d51e,3f8286c5fb1..d93e27c3f22
--- a/ui/src/config/section/image.js
+++ b/ui/src/config/section/image.js
@@@ -58,11 -58,11 +58,11 @@@ export default
return fields
},
details: () => {
- var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'arch', 'format', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
+ var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'arch', 'format', 'externalprovisioner', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
'crossZones', 'templatetype', 'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
- 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'forcks']
- 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url']
++ 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url', 'forcks']
if (['Admin'].includes(store.getters.userInfo.roletype)) {
- fields.push('templatetag', 'templatetype', 'url')
+ fields.push('templatetag', 'templatetype')
}
return fields
},
diff --cc ui/src/views/auth/ForgotPassword.vue
index 78af0c3d9f1,1e817e01a6e..a508934070a
--- a/ui/src/views/auth/ForgotPassword.vue
+++ b/ui/src/views/auth/ForgotPassword.vue
@@@ -159,10 -159,10 +159,10 @@@ export default
if (!loginParams.domain) {
loginParams.domain = '/'
}
- api('forgotPassword', {}, 'POST', loginParams)
+ postAPI('forgotPassword', loginParams)
.finally(() => {
this.$message.success(this.$t('message.forgot.password.success'))
- this.$router.push({ path: '/login' }).catch(() => {})
+ this.$router.replace({ path: '/user/login' })
})
}).catch(error => {
this.formRef.value.scrollToField(error.errorFields[0].name)