This is an automated email from the ASF dual-hosted git repository. sureshanaparti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 1bff543e58e626a7bcdea265284c8f3bcf57c7b0 Merge: b744824f658 c1af36f8fc9 Author: Suresh Kumar Anaparti <[email protected]> AuthorDate: Fri Mar 27 01:25:42 2026 +0530 Merge branch '4.22' api/src/main/java/com/cloud/vm/UserVmService.java | 3 +- api/src/main/java/com/cloud/vm/VirtualMachine.java | 3 + .../api/command/admin/vm/ImportVmCmd.java | 12 ++ .../api/command/user/guest/ListGuestOsCmd.java | 9 ++ .../api/command/user/vpc/CreateStaticRouteCmd.java | 1 - .../api/response/UnmanagedInstanceResponse.java | 24 ++++ .../volume/VolumeImportUnmanageService.java | 13 +- .../apache/cloudstack/vm/UnmanagedInstanceTO.java | 19 +++ .../apache/cloudstack/vm/UnmanagedVMsManager.java | 2 + .../engine/orchestration/NetworkOrchestrator.java | 7 +- .../java/com/cloud/storage/dao/GuestOSDao.java | 2 +- .../java/com/cloud/storage/dao/GuestOSDaoImpl.java | 6 +- .../main/java/com/cloud/storage/dao/VolumeDao.java | 8 ++ .../java/com/cloud/storage/dao/VolumeDaoImpl.java | 12 ++ .../com/cloud/upgrade/dao/Upgrade42200to42210.java | 51 ++++++++ .../datastore/db/SnapshotDataStoreDaoImpl.java | 14 +-- .../META-INF/db/schema-42200to42210-cleanup.sql | 2 + .../resources/META-INF/db/schema-42200to42210.sql | 2 + .../db/views/cloud.account_netstats_view.sql | 31 ----- .../META-INF/db/views/cloud.account_view.sql | 15 ++- .../motion/StorageSystemDataMotionStrategy.java | 4 +- .../wrapper/LibvirtGetRemoteVmsCommandWrapper.java | 2 + ...LibvirtGetUnmanagedInstancesCommandWrapper.java | 2 + .../java/org/apache/cloudstack/saml/SAMLUtils.java | 3 + .../main/java/com/cloud/api/ApiResponseHelper.java | 17 ++- .../deploy/DeploymentPlanningManagerImpl.java | 4 +- .../com/cloud/server/ManagementServerImpl.java | 33 ++++-- .../com/cloud/template/TemplateManagerImpl.java | 3 + .../src/main/java/com/cloud/vm/UserVmManager.java | 5 + .../main/java/com/cloud/vm/UserVmManagerImpl.java | 132 ++++++++++++++------- .../volume/VolumeImportUnmanageManagerImpl.java | 15 ++- .../cloudstack/vm/UnmanagedVMsManagerImpl.java | 100 ++++------------ .../java/com/cloud/vm/UserVmManagerImplTest.java | 54 +++++++++ .../cloudstack/vm/UnmanagedVMsManagerImplTest.java | 55 ++++++++- test/integration/smoke/test_secondary_storage.py | 16 ++- ui/public/locales/en.json | 1 + ui/src/permission.js | 1 + ui/src/views/compute/DeployVM.vue | 6 + .../compute/wizard/SecurityGroupSelection.vue | 26 +++- ui/src/views/image/TemplateZones.vue | 14 ++- ui/src/views/network/CreateNetwork.vue | 2 +- ui/src/views/network/VpcTiersTab.vue | 10 +- ui/src/views/tools/ImportUnmanagedInstance.vue | 37 +++++- ui/src/views/tools/ManageInstances.vue | 21 +++- .../com/cloud/hypervisor/vmware/mo/BaseMO.java | 27 ++++- .../cloud/hypervisor/vmware/util/VmwareHelper.java | 16 ++- .../hypervisor/vmware/util/VmwareHelperTest.java | 23 ++++ 47 files changed, 645 insertions(+), 220 deletions(-) diff --cc server/src/main/java/com/cloud/server/ManagementServerImpl.java index f8c4d1d44d4,4875002074c..15286eaaf54 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@@ -43,7 -43,7 +43,8 @@@ import javax.crypto.spec.SecretKeySpec import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.acl.ApiKeyPairVO; + import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.network.vpc.VpcVO; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker; diff --cc server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4597ef81965,4cb721666bd..f4ea7bd9311 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@@ -1172,9 -1192,9 +1172,9 @@@ public class UserVmManagerImpl extends if (dc.getNetworkType() == DataCenter.NetworkType.Advanced) { //List all networks of vm List<Long> vmNetworks = _vmNetworkMapDao.getNetworks(vmId); - List<DomainRouterVO> routers = new ArrayList<DomainRouterVO>(); + List<DomainRouterVO> routers = new ArrayList<>(); //List the stopped routers - for(long vmNetworkId : vmNetworks) { + for (long vmNetworkId : vmNetworks) { List<DomainRouterVO> router = _routerDao.listStopped(vmNetworkId); routers.addAll(router); } diff --cc server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java index f7439386fab,783be00c449..4e6627f4640 --- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java +++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java @@@ -198,6 -195,6 +198,7 @@@ import com.cloud.utils.db.EntityManager import com.cloud.utils.db.UUIDManager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionProxyObject; ++import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDetailsDao; @@@ -1501,6 -1477,9 +1502,7 @@@ public class UserVmManagerImplTest when(cmd.getVmId()).thenReturn(vmId); when(cmd.getTemplateId()).thenReturn(2L); when(userVmDao.findById(vmId)).thenReturn(userVmVoMock); - KubernetesServiceHelper helper = mock(KubernetesServiceHelper.class); - when(helper.findByVmId(anyLong())).thenReturn(null); - userVmManagerImpl.setKubernetesServiceHelpers(Collections.singletonList(helper)); ++ Mockito.doReturn(false).when(userVmManagerImpl).isVMPartOfAnyCKSCluster(userVmVoMock); userVmManagerImpl.restoreVM(cmd); } @@@ -4206,49 -4182,55 +4208,101 @@@ verify(userVmDao, times(1)).releaseFromLockTable(vmId); } + @Test + public void updateVmExtraConfigCleansUpWhenCleanupFlagIsTrue() { + UserVmVO userVm = mock(UserVmVO.class); + when(userVm.getUuid()).thenReturn("test-uuid"); + when(userVm.getId()).thenReturn(1L); + + userVmManagerImpl.updateVmExtraConfig(userVm, "someConfig", true); + + verify(vmInstanceDetailsDao, times(1)).removeDetailsWithPrefix(1L, ApiConstants.EXTRA_CONFIG); + verifyNoMoreInteractions(vmInstanceDetailsDao); + } + + @Test + public void updateVmExtraConfigAddsConfigWhenValidAndEnabled() { + UserVmVO userVm = mock(UserVmVO.class); + when(userVm.getUuid()).thenReturn("test-uuid"); + when(userVm.getAccountId()).thenReturn(1L); + when(userVm.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + doNothing().when(userVmManagerImpl).persistExtraConfigKvm(anyString(), eq(userVm)); + updateDefaultConfigValue(UserVmManagerImpl.EnableAdditionalVmConfig, true, false); + + userVmManagerImpl.updateVmExtraConfig(userVm, "validConfig", false); + + verify(vmInstanceDetailsDao, never()).removeDetailsWithPrefix(anyLong(), anyString()); + verify(userVmManagerImpl, times(1)).addExtraConfig(userVm, "validConfig"); + } + + @Test(expected = InvalidParameterValueException.class) + public void updateVmExtraConfigThrowsExceptionWhenConfigDisabled() { + UserVmVO userVm = mock(UserVmVO.class); + when(userVm.getAccountId()).thenReturn(1L); + updateDefaultConfigValue(UserVmManagerImpl.EnableAdditionalVmConfig, false, false); + + userVmManagerImpl.updateVmExtraConfig(userVm, "validConfig", false); + } + + @Test + public void updateVmExtraConfigDoesNothingWhenExtraConfigIsBlank() { + UserVmVO userVm = mock(UserVmVO.class); + + userVmManagerImpl.updateVmExtraConfig(userVm, "", false); + + verify(vmInstanceDetailsDao, never()).removeDetailsWithPrefix(anyLong(), anyString()); + verify(userVmManagerImpl, never()).addExtraConfig(any(UserVmVO.class), anyString()); + } ++ + @Test + public void testTransitionExpungingToErrorVmInExpungingState() throws Exception { + UserVmVO vm = mock(UserVmVO.class); + when(vm.getState()).thenReturn(VirtualMachine.State.Expunging); + when(vm.getUuid()).thenReturn("test-uuid"); + when(userVmDao.findById(vmId)).thenReturn(vm); + when(virtualMachineManager.stateTransitTo(eq(vm), eq(VirtualMachine.Event.OperationFailedToError), eq(null))).thenReturn(true); + + java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class); + method.setAccessible(true); + method.invoke(userVmManagerImpl, vmId); + + Mockito.verify(virtualMachineManager).stateTransitTo(vm, VirtualMachine.Event.OperationFailedToError, null); + } + + @Test + public void testTransitionExpungingToErrorVmNotInExpungingState() throws Exception { + UserVmVO vm = mock(UserVmVO.class); + when(vm.getState()).thenReturn(VirtualMachine.State.Stopped); + when(userVmDao.findById(vmId)).thenReturn(vm); + + java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class); + method.setAccessible(true); + method.invoke(userVmManagerImpl, vmId); + + Mockito.verify(virtualMachineManager, Mockito.never()).stateTransitTo(any(VirtualMachine.class), any(VirtualMachine.Event.class), any()); + } + + @Test + public void testTransitionExpungingToErrorVmNotFound() throws Exception { + when(userVmDao.findById(vmId)).thenReturn(null); + + java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class); + method.setAccessible(true); + method.invoke(userVmManagerImpl, vmId); + + Mockito.verify(virtualMachineManager, Mockito.never()).stateTransitTo(any(VirtualMachine.class), any(VirtualMachine.Event.class), any()); + } + + @Test + public void testTransitionExpungingToErrorHandlesNoTransitionException() throws Exception { + UserVmVO vm = mock(UserVmVO.class); + when(vm.getState()).thenReturn(VirtualMachine.State.Expunging); + when(userVmDao.findById(vmId)).thenReturn(vm); + when(virtualMachineManager.stateTransitTo(eq(vm), eq(VirtualMachine.Event.OperationFailedToError), eq(null))) + .thenThrow(new NoTransitionException("no transition")); + + java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class); + method.setAccessible(true); + method.invoke(userVmManagerImpl, vmId); + } } diff --cc ui/src/permission.js index 671d6626b93,eeb36c57117..0b87de92c6b --- a/ui/src/permission.js +++ b/ui/src/permission.js @@@ -93,17 -93,8 +93,18 @@@ router.beforeEach((to, from, next) => return } store.commit('SET_LOGIN_FLAG', true) + store.commit('SET_MS_ID', Cookies.get('managementserverid')) } + // store already loaded + if (store.getters.passwordChangeRequired) { + if (to.path === '/user/forceChangePassword') { + next() + } else { + next({ path: '/user/forceChangePassword' }) + NProgress.done() + } + return + } if (Object.keys(store.getters.apis).length === 0) { const cachedApis = vueProps.$localStorage.get(APIS, {}) if (Object.keys(cachedApis).length > 0) {
