From 04875f151771b6b6fdf97d4a4f2690fbeda025d2 Mon Sep 17 00:00:00 2001 From: Nicolas Vazquez Date: Fri, 9 Jan 2026 13:50:27 -0300 Subject: [PATCH 1/8] Improve logs for VM migrations (#12332) --- .../cloud/vm/VirtualMachineManagerImpl.java | 29 ++++++++++++++----- .../wrapper/LibvirtMigrateCommandWrapper.java | 9 +++++- ...virtPrepareForMigrationCommandWrapper.java | 4 +++ .../java/com/cloud/vm/UserVmManagerImpl.java | 2 ++ 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index f9238fa0e71..86f45630611 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3053,7 +3053,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } protected void migrate(final VMInstanceVO vm, final long srcHostId, final DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException { - logger.info("Migrating {} to {}", vm, dest); + logger.info("Start preparing migration of the VM: {} to {}", vm, dest); final long dstHostId = dest.getHost().getId(); final Host fromHost = _hostDao.findById(srcHostId); if (fromHost == null) { @@ -3118,9 +3118,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (pfma == null || !pfma.getResult()) { final String details = pfma != null ? pfma.getDetails() : "null answer returned"; final String msg = "Unable to prepare for migration due to " + details; + logger.error("Failed to prepare destination host {} for migration of VM {} : {}", dstHostId, vm.getInstanceName(), details); pfma = null; throw new AgentUnavailableException(msg, dstHostId); } + logger.debug("Successfully prepared destination host {} for migration of VM {} ", dstHostId, vm.getInstanceName()); } catch (final OperationTimedoutException e1) { throw new AgentUnavailableException("Operation timed out", dstHostId); } finally { @@ -3141,18 +3143,23 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac volumeMgr.release(vm.getId(), dstHostId); } - logger.info("Migration cancelled because state has changed: {}", vm); - throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm); + String msg = "Migration cancelled because state has changed: " + vm; + logger.warn(msg); + throw new ConcurrentOperationException(msg); } } catch (final NoTransitionException e1) { _networkMgr.rollbackNicForMigration(vmSrc, profile); volumeMgr.release(vm.getId(), dstHostId); - logger.info("Migration cancelled because {}", e1.getMessage()); + String msg = String.format("Migration cancelled for VM %s due to state transition failure: %s", + vm.getInstanceName(), e1.getMessage()); + logger.warn(msg, e1); throw new ConcurrentOperationException("Migration cancelled because " + e1.getMessage()); } catch (final CloudRuntimeException e2) { _networkMgr.rollbackNicForMigration(vmSrc, profile); volumeMgr.release(vm.getId(), dstHostId); - logger.info("Migration cancelled because {}", e2.getMessage()); + String msg = String.format("Migration cancelled for VM %s due to runtime exception: %s", + vm.getInstanceName(), e2.getMessage()); + logger.error(msg, e2); work.setStep(Step.Done); _workDao.update(work.getId(), work); try { @@ -3172,8 +3179,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac final Answer ma = _agentMgr.send(vm.getLastHostId(), mc); if (ma == null || !ma.getResult()) { final String details = ma != null ? ma.getDetails() : "null answer returned"; + String msg = String.format("Migration command failed for VM %s on source host id=%s to destination host %s: %s", + vm.getInstanceName(), vm.getLastHostId(), dstHostId, details); + logger.error(msg); throw new CloudRuntimeException(details); } + logger.info("Migration command successful for VM {}", vm.getInstanceName()); } catch (final OperationTimedoutException e) { boolean success = false; if (HypervisorType.KVM.equals(vm.getHypervisorType())) { @@ -3210,7 +3221,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac try { if (!checkVmOnHost(vm, dstHostId)) { - logger.error("Unable to complete migration for {}", vm); + logger.error("Migration verification failed for VM {} : VM not found on destination host {} ", vm.getInstanceName(), dstHostId); try { _agentMgr.send(srcHostId, new Commands(cleanup(vm, dpdkInterfaceMapping)), null); } catch (final AgentUnavailableException e) { @@ -3225,7 +3236,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac migrated = true; } finally { if (!migrated) { - logger.info("Migration was unsuccessful. Cleaning up: {}", vm); + logger.info("Migration was unsuccessful. Cleaning up: {}", vm); _networkMgr.rollbackNicForMigration(vmSrc, profile); volumeMgr.release(vm.getId(), dstHostId); // deallocate GPU devices for the VM on the destination host @@ -3237,7 +3248,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac try { _agentMgr.send(dstHostId, new Commands(cleanup(vm, dpdkInterfaceMapping)), null); } catch (final AgentUnavailableException ae) { - logger.warn("Looks like the destination Host is unavailable for cleanup", ae); + logger.warn("Destination host {} unavailable for cleanup after failed migration of VM {}", dstHostId, vm.getInstanceName(), ae); } _networkMgr.setHypervisorHostname(profile, dest, false); try { @@ -3246,6 +3257,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac logger.warn(e.getMessage()); } } else { + logger.info("Migration completed successfully for VM %s" + vm); _networkMgr.commitNicForMigration(vmSrc, profile); volumeMgr.release(vm.getId(), srcHostId); // deallocate GPU devices for the VM on the src host after migration is complete @@ -3276,6 +3288,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac migrateCommand.setVlanToPersistenceMap(vlanToPersistenceMap); } + logger.debug("Setting auto convergence to: {}", StorageManager.KvmAutoConvergence.value()); migrateCommand.setAutoConvergence(StorageManager.KvmAutoConvergence.value()); migrateCommand.setHostGuid(destination.getHost().getGuid()); diff --git 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 index 859de5143f9..81328d6ffb9 100644 --- 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 @@ -278,17 +278,20 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper 0 && sleeptime > migrateWait * 1000) { DomainState state = null; try { state = dm.getInfo().state; + logger.info("VM domain state when trying to abort migration : {}", state); } 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) { 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; @@ -303,10 +306,12 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper 0 && sleeptime > migratePauseAfter) { DomainState state = null; try { state = dm.getInfo().state; + logger.info("VM domain state when trying to pause VM for migration: {}", state); } catch (final LibvirtException e) { logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage()); } @@ -381,6 +386,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper Date: Mon, 12 Jan 2026 12:11:45 +0530 Subject: [PATCH 2/8] [UI] Fix for the login url with nested redirect parameters (#12356) --- ui/src/utils/request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js index 42b26c9785b..2317aac0446 100644 --- a/ui/src/utils/request.js +++ b/ui/src/utils/request.js @@ -54,7 +54,7 @@ const err = (error) => { if (response.config && response.config.params && ['forgotPassword', 'listIdps', 'cloudianIsEnabled'].includes(response.config.params.command)) { return } - const originalPath = router.currentRoute.value.fullPath + const originalPath = router.currentRoute.value.path for (const key in response.data) { if (key.includes('response')) { if (response.data[key].errortext.includes('not available for user')) { From db1c7d678cc5505a926193e119991eb87d86cf33 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 12 Jan 2026 12:51:19 +0530 Subject: [PATCH 3/8] Updated protobuf version to 3.25.5, and protobuf & jackson maven dependencies (#12389) --- plugins/hypervisors/kvm/pom.xml | 25 +++++++++++++++++++++++++ pom.xml | 12 ++++++++++++ utils/pom.xml | 5 +++++ 3 files changed, 42 insertions(+) diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml index 096c0362ee4..e2e1721b3a7 100644 --- a/plugins/hypervisors/kvm/pom.xml +++ b/plugins/hypervisors/kvm/pom.xml @@ -67,6 +67,31 @@ java-linstor ${cs.java-linstor.version} + + com.fasterxml.jackson.core + jackson-core + ${cs.jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${cs.jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${cs.jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${cs.jackson.version} + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + ${cs.jackson.version} + net.java.dev.jna jna diff --git a/pom.xml b/pom.xml index b51ed12fded..6985108302d 100644 --- a/pom.xml +++ b/pom.xml @@ -190,6 +190,7 @@ 5.3.26 0.5.4 3.1.7 + 3.25.5 @@ -727,6 +728,17 @@ xml-apis 2.0.2 + + + com.google.protobuf + protobuf-java + ${cs.protobuf.version} + + + com.google.protobuf + protobuf-java-util + ${cs.protobuf.version} + com.linbit.linstor.api java-linstor diff --git a/utils/pom.xml b/utils/pom.xml index 6c367364600..6b8b1249423 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -196,6 +196,11 @@ jackson-databind ${cs.jackson.version} + + com.fasterxml.jackson.dataformat + jackson-dataformat-cbor + ${cs.jackson.version} + org.apache.commons commons-compress From 0e6d2d986b7022648bdb5550060aeb7b7fe76bf4 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 12 Jan 2026 13:23:37 +0530 Subject: [PATCH 4/8] ui: prevent calling listConfigurations when not allowed (#11704) By default, normal users won't have access to listConfigurations API, therefore, UI should not call it when access is not there. Signed-off-by: Abhishek Kumar --- ui/src/store/modules/user.js | 18 ++++++++++-------- .../views/image/RegisterOrUploadTemplate.vue | 3 +++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js index fc1b0dc25a9..21cd603e378 100644 --- a/ui/src/store/modules/user.js +++ b/ui/src/store/modules/user.js @@ -539,14 +539,16 @@ const user = { reject(error) }) - api('listConfigurations', { name: 'hypervisor.custom.display.name' }).then(json => { - if (json.listconfigurationsresponse.configuration !== null) { - const config = json.listconfigurationsresponse.configuration[0] - commit('SET_CUSTOM_HYPERVISOR_NAME', config.value) - } - }).catch(error => { - reject(error) - }) + if ('listConfigurations' in store.getters.apis) { + api('listConfigurations', { name: 'hypervisor.custom.display.name' }).then(json => { + if (json.listconfigurationsresponse.configuration !== null) { + const config = json.listconfigurationsresponse.configuration[0] + commit('SET_CUSTOM_HYPERVISOR_NAME', config.value) + } + }).catch(error => { + reject(error) + }) + } }) }, UpdateConfiguration ({ commit }) { diff --git a/ui/src/views/image/RegisterOrUploadTemplate.vue b/ui/src/views/image/RegisterOrUploadTemplate.vue index c3f812773be..76df7b246aa 100644 --- a/ui/src/views/image/RegisterOrUploadTemplate.vue +++ b/ui/src/views/image/RegisterOrUploadTemplate.vue @@ -646,6 +646,9 @@ export default { }) }, fetchCustomHypervisorName () { + if (!('listConfigurations' in this.$store.getters.apis)) { + return + } const params = { name: 'hypervisor.custom.display.name' } From c7cfeb5caa1a5d40864ae7f7530bf6563cea6f31 Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Mon, 12 Jan 2026 13:43:12 +0530 Subject: [PATCH 5/8] fix location constraint ceph error (#12285) --- .../storage/datastore/driver/CephObjectStoreDriverImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/storage/object/ceph/src/main/java/org/apache/cloudstack/storage/datastore/driver/CephObjectStoreDriverImpl.java b/plugins/storage/object/ceph/src/main/java/org/apache/cloudstack/storage/datastore/driver/CephObjectStoreDriverImpl.java index 12920e37907..9af558cf6e3 100644 --- a/plugins/storage/object/ceph/src/main/java/org/apache/cloudstack/storage/datastore/driver/CephObjectStoreDriverImpl.java +++ b/plugins/storage/object/ceph/src/main/java/org/apache/cloudstack/storage/datastore/driver/CephObjectStoreDriverImpl.java @@ -350,7 +350,7 @@ public class CephObjectStoreDriverImpl extends BaseObjectStoreDriverImpl { new AWSStaticCredentialsProvider( new BasicAWSCredentials(accessKey, secretKey))) .withEndpointConfiguration( - new AwsClientBuilder.EndpointConfiguration(url, null)) + new AwsClientBuilder.EndpointConfiguration(url, "us-east-1")) .build(); if (client == null) { From 2b373a4659526a43db0ed30ca39927b0183c95de Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 12 Jan 2026 14:18:35 +0530 Subject: [PATCH 6/8] [UI] Fix primary storage details display when the uuid has divergent pattern (#12307) * [UI] Fix primary storage details display when the uuid has different pattern (eg. for pools with SolidFireShared provider) * Fix on refresh --------- Co-authored-by: vishesh92 --- ui/src/components/view/InfoCard.vue | 2 +- ui/src/components/view/ListView.vue | 4 ++-- ui/src/components/view/VolumesTab.vue | 2 +- ui/src/components/widgets/Breadcrumb.vue | 2 +- ui/src/config/router.js | 4 ++-- ui/src/views/image/IsoZones.vue | 2 +- ui/src/views/image/TemplateZones.vue | 2 +- ui/src/views/storage/SnapshotZones.vue | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue index f1efcaef281..0272df028a3 100644 --- a/ui/src/components/view/InfoCard.vue +++ b/ui/src/components/view/InfoCard.vue @@ -622,7 +622,7 @@
{{ $t('label.storagepool') }}
- {{ resource.storage || resource.storageid }} + {{ resource.storage || resource.storageid }} {{ resource.storage || resource.storageid }} {{ resource.storagetype }} diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 0109784047a..a02fb5569ed 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -94,7 +94,7 @@ {{ $t(text.toLowerCase()) }} - {{ text }} + {{ text }} {{ text }}   @@ -306,7 +306,7 @@ {{ text }} diff --git a/ui/src/components/widgets/Breadcrumb.vue b/ui/src/components/widgets/Breadcrumb.vue index 147e779502b..4723417f539 100644 --- a/ui/src/components/widgets/Breadcrumb.vue +++ b/ui/src/components/widgets/Breadcrumb.vue @@ -100,7 +100,7 @@ export default { this.breadList = [] this.$route.matched.forEach((item, idx) => { const parent = this.$route.matched[idx - 1] - if (item && parent && parent.name !== 'index' && !item.path.endsWith(':id')) { + if (item && parent && parent.name !== 'index' && !item.path.endsWith(':id') && !item.path.endsWith(':id(.*)')) { this.breadList.pop() } this.breadList.push(item) diff --git a/ui/src/config/router.js b/ui/src/config/router.js index aa85f452b73..f8ff3e00138 100644 --- a/ui/src/config/router.js +++ b/ui/src/config/router.js @@ -90,7 +90,7 @@ function generateRouterMap (section) { hideChildrenInMenu: true, children: [ { - path: '/' + child.name + '/:id', + path: '/' + child.name + '/:id(.*)', hidden: child.hidden, meta: { title: child.title, @@ -145,7 +145,7 @@ function generateRouterMap (section) { map.meta.tabs = section.tabs map.children = [{ - path: '/' + section.name + '/:id', + path: '/' + section.name + '/:id(.*)', actions: section.actions ? section.actions : [], meta: { title: section.title, diff --git a/ui/src/views/image/IsoZones.vue b/ui/src/views/image/IsoZones.vue index 75eac8fd97f..f14ec92b3f6 100644 --- a/ui/src/views/image/IsoZones.vue +++ b/ui/src/views/image/IsoZones.vue @@ -90,7 +90,7 @@ :rowKey="record => record.zoneid">