From dd0b863e22579caa77e399855df690d350c80d3e Mon Sep 17 00:00:00 2001 From: Edward-x <30854794+YLChen-007@users.noreply.github.com> Date: Wed, 28 Jan 2026 12:41:23 +0800 Subject: [PATCH 1/7] sensitive information leak to log (#12018) * sensitive information leak to log * Update agent/src/main/java/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java * Update core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java * Update engine/schema/src/main/java/com/cloud/upgrade/DatabaseCreator.java * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java * Update utils/src/main/java/com/cloud/utils/UriUtils.java Co-authored-by: dahn * Update plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java Co-authored-by: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> * Sync with 4.20 and fix conflict in BaremetalPingPxeResource * Apply suggestions from code review Co-authored-by: Suresh Kumar Anaparti --------- Co-authored-by: chenyoulong20g@ict.ac.cn Co-authored-by: dahn Co-authored-by: dahn Co-authored-by: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Co-authored-by: Suresh Kumar Anaparti --- .../resource/consoleproxy/ConsoleProxyResource.java | 2 +- .../networkservice/BaremetalDnsmasqResource.java | 4 ++-- .../networkservice/BaremetalKickStartPxeResource.java | 6 +++--- .../networkservice/BaremetalPingPxeResource.java | 10 +++++----- utils/src/main/java/com/cloud/utils/UriUtils.java | 8 ++++++-- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/agent/src/main/java/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java b/agent/src/main/java/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java index b0b1e487a26..83b11418f2c 100644 --- a/agent/src/main/java/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java +++ b/agent/src/main/java/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java @@ -331,7 +331,7 @@ public class ConsoleProxyResource extends ServerResourceBase implements ServerRe final Object resource = this; logger.info("Building class loader for com.cloud.consoleproxy.ConsoleProxy"); if (consoleProxyMain == null) { - logger.info("Running com.cloud.consoleproxy.ConsoleProxy with encryptor password={}", encryptorPassword); + logger.info("Running com.cloud.consoleproxy.ConsoleProxy"); consoleProxyMain = new Thread(new ManagedContextRunnable() { @Override protected void runInContext() { diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java index 51acfe93d39..8e7efedfca3 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java @@ -46,10 +46,10 @@ public class BaremetalDnsmasqResource extends BaremetalDhcpResourceBase { com.trilead.ssh2.Connection sshConnection = null; try { super.configure(name, params); - logger.debug(String.format("Trying to connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s)", _ip, _username, _password)); + logger.debug(String.format("Trying to connect to DHCP server(IP=%1$s, username=%2$s", _ip, _username)); sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); if (sshConnection == null) { - throw new ConfigurationException(String.format("Cannot connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + throw new ConfigurationException(String.format("Cannot connect to DHCP server(IP=%1$s, username=%2$s", _ip, _username)); } if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -f '/usr/sbin/dnsmasq' ]")) { diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java index 3775f4effc1..88c4dea96b3 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java @@ -130,8 +130,8 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase { sshConnection.connect(null, 60000, 60000); if (!sshConnection.authenticateWithPassword(_username, _password)) { - logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + logger.debug("SSH Failed to authenticate with user {} credentials", _username); + throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s", _ip, _username)); } String script = String.format("python /usr/bin/baremetal_user_data.py '%s'", arg); @@ -167,7 +167,7 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase { sshConnection.connect(null, 60000, 60000); if (!sshConnection.authenticateWithPassword(_username, _password)) { logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s", _ip, _username)); } String copyTo = String.format("%s/%s", _tftpDir, cmd.getTemplateUuid()); diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java index 96b2dbfeb93..a54cd4a1a11 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java @@ -101,7 +101,7 @@ public class BaremetalPingPxeResource extends BaremetalPxeResourceBase { sshConnection.connect(null, 60000, 60000); if (!sshConnection.authenticateWithPassword(_username, _password)) { logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, "******")); + throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=******", _ip, _username)); } String cmd = String.format("[ -f /%1$s/pxelinux.0 ] && [ -f /%2$s/kernel ] && [ -f /%3$s/initrd.gz ] ", _tftpDir, _tftpDir, _tftpDir); @@ -150,8 +150,8 @@ public class BaremetalPingPxeResource extends BaremetalPxeResourceBase { try { sshConnection.connect(null, 60000, 60000); if (!sshConnection.authenticateWithPassword(_username, _password)) { - logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + logger.debug("SSH Failed to authenticate with user {} credentials", _username); + throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s", _ip, _username)); } String script = @@ -179,7 +179,7 @@ public class BaremetalPingPxeResource extends BaremetalPxeResourceBase { sshConnection.connect(null, 60000, 60000); if (!sshConnection.authenticateWithPassword(_username, _password)) { logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s", _ip, _username)); } String script = @@ -237,7 +237,7 @@ public class BaremetalPingPxeResource extends BaremetalPxeResourceBase { sshConnection.connect(null, 60000, 60000); if (!sshConnection.authenticateWithPassword(_username, _password)) { logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s", _ip, _username)); } String script = String.format("python /usr/bin/baremetal_user_data.py '%s'", arg); diff --git a/utils/src/main/java/com/cloud/utils/UriUtils.java b/utils/src/main/java/com/cloud/utils/UriUtils.java index 961c121597f..4722e3c540a 100644 --- a/utils/src/main/java/com/cloud/utils/UriUtils.java +++ b/utils/src/main/java/com/cloud/utils/UriUtils.java @@ -500,8 +500,12 @@ public class UriUtils { if ((user != null) && (password != null)) { httpclient.getParams().setAuthenticationPreemptive(true); Credentials defaultcreds = new UsernamePasswordCredentials(user, password); - httpclient.getState().setCredentials(new AuthScope(hostAndPort.first(), hostAndPort.second(), AuthScope.ANY_REALM), defaultcreds); - LOGGER.info("Added username=" + user + ", password=" + password + "for host " + hostAndPort.first() + ":" + hostAndPort.second()); + httpclient.getState().setCredentials( + new AuthScope(hostAndPort.first(), hostAndPort.second(), AuthScope.ANY_REALM), defaultcreds); + LOGGER.info("Added username={} along with password for host {}:{}" + , user + , hostAndPort.first() + , hostAndPort.second()); } // Execute the method. GetMethod method = new GetMethod(url); From 062b98a51eca7da6b6083cbb31c2fb0608448386 Mon Sep 17 00:00:00 2001 From: cheng102e <38267524+cheng102e@users.noreply.github.com> Date: Wed, 28 Jan 2026 12:45:11 +0800 Subject: [PATCH 2/7] fix: clean magic value, and update if-else to switch (#8848) * fix: clean magic value, and update if-else to switch * fix: return the (String args[]) * review --------- Co-authored-by: jiejc1 Co-authored-by: Suresh Kumar Anaparti --- .../src/main/java/common/Client.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/services/console-proxy/rdpconsole/src/main/java/common/Client.java b/services/console-proxy/rdpconsole/src/main/java/common/Client.java index 742f5c9f0cd..972d5d753e8 100644 --- a/services/console-proxy/rdpconsole/src/main/java/common/Client.java +++ b/services/console-proxy/rdpconsole/src/main/java/common/Client.java @@ -210,7 +210,6 @@ public class Client { public void runClient(String[] args) { try { - Protocol protocol = parseOptions(args); if (protocol == Protocol.NONE) return; @@ -299,21 +298,28 @@ public class Client { private Protocol parseOptions(String[] args) { String protocolName = (args.length > 0) ? args[0] : ""; - Protocol protocol = Protocol.NONE; + Protocol protocol; Option[] options; - if (protocolName.equals("vnc")) { - protocol = Protocol.VNC; - options = join(commonOptions, vncOptions); - } else if (protocolName.equals("rdp")) { - protocol = Protocol.RDP; - options = join(commonOptions, rdpOptions); - } else if (protocolName.equals("hyperv")) { - protocol = Protocol.HYPERV; - options = join(commonOptions, hyperVOptions); - } else { - help(); - return Protocol.NONE; + try { + protocol = Protocol.valueOf(protocolName); + } catch (IllegalArgumentException e) { + protocol = Protocol.NONE; + } + + switch (protocol) { + case VNC: + options = join(commonOptions, vncOptions); + break; + case RDP: + options = join(commonOptions, rdpOptions); + break; + case HYPERV: + options = join(commonOptions, hyperVOptions); + break; + default: + help(); + return Protocol.NONE; } // Parse all options for given protocol From 21d5c10850111cd2e76d783b95b090da623ae024 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 28 Jan 2026 10:55:59 +0530 Subject: [PATCH 3/7] Apply reordered ACL list to VR router (#12525) This PR address #9398 --- .../network/element/VpcVirtualRouterElement.java | 10 +++++++++- .../cloud/network/vpc/NetworkACLServiceImpl.java | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java index 3d613fca18e..f393ef8a129 100644 --- a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java @@ -550,7 +550,15 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc @Override public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { - return true; + boolean result = true; + try { + for (Network network : networks) { + result = result && applyNetworkACLs(network, networkACLItems); + } + } catch (ResourceUnavailableException ex) { + result = false; + } + return result; } @Override diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java index ecb164018ac..7460ae87d44 100644 --- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java @@ -109,6 +109,8 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ private NsxProviderDao nsxProviderDao; @Inject private NetrisProviderDao netrisProviderDao; + @Inject + private VpcManager vpcManager; private String supportedProtocolsForAclRules = "tcp,udp,icmp,all"; @@ -1037,13 +1039,20 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ if (Objects.isNull(vpc)) { return networkACLItem; } + List networks = _networkDao.listByAclId(lockedAcl.getId()); + if (networks.isEmpty()) { + return networkACLItem; + } + final DataCenter dc = _entityMgr.findById(DataCenter.class, vpc.getZoneId()); final NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dc.getId()); final NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(dc.getId()); - List networks = _networkDao.listByAclId(lockedAcl.getId()); - if (ObjectUtils.anyNotNull(nsxProvider, netrisProvider) && !networks.isEmpty()) { + boolean isVpcNetworkACLProvider = vpcManager.isProviderSupportServiceInVpc(vpc.getId(), Network.Service.NetworkACL, Network.Provider.VPCVirtualRouter); + + if (ObjectUtils.anyNotNull(nsxProvider, netrisProvider) || isVpcNetworkACLProvider) { allAclRules = getAllAclRulesSortedByNumber(lockedAcl.getId()); - Network.Provider networkProvider = nsxProvider != null ? Network.Provider.Nsx : Network.Provider.Netris; + Network.Provider networkProvider = isVpcNetworkACLProvider ? Network.Provider.VPCVirtualRouter + : (nsxProvider != null ? Network.Provider.Nsx : Network.Provider.Netris); _networkAclMgr.reorderAclRules(vpc, networks, allAclRules, networkProvider); } return networkACLItem; From 572aa1956493d58a0efa283d2f75d876d92a5ad9 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 28 Jan 2026 11:01:53 +0530 Subject: [PATCH 4/7] ui: show usage server restart message on usage config change (#11969) Fixes #10853 --------- Signed-off-by: Abhishek Kumar --- ui/public/locales/en.json | 1 + ui/src/components/view/ListView.vue | 10 +--------- ui/src/utils/plugins.js | 11 +++++++++++ ui/src/views/setting/ConfigurationValue.vue | 20 ++------------------ 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 275b8dbb0fe..74715496434 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -3735,6 +3735,7 @@ "message.resource.not.found": "Resource not found.", "message.restart.mgmt.server": "Please restart your management server(s) for your new settings to take effect.", "message.restart.network": "All services provided by this Network will be interrupted. Please confirm that you want to restart this Network.", +"message.restart.usage.server": "Please restart your usage server(s) for your new settings to take effect.", "message.restart.vm.to.update.settings": "Update in fields other than name and display name will require the Instance to be restarted.", "message.restart.vpc": "Please confirm that you want to restart the VPC.", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The Networks will not be available for a couple of minutes.

", diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 168e355cbc8..79ec5a18207 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -1234,15 +1234,7 @@ export default { this.editableValueKey = null this.$store.dispatch('RefreshFeatures') this.$messageConfigSuccess(`${this.$t('message.setting.updated')} ${record.name}`, record) - if (json.updateconfigurationresponse && - json.updateconfigurationresponse.configuration && - !json.updateconfigurationresponse.configuration.isdynamic && - ['Admin'].includes(this.$store.getters.userInfo.roletype)) { - this.$notification.warning({ - message: this.$t('label.status'), - description: this.$t('message.restart.mgmt.server') - }) - } + this.$notifyConfigurationValueChange(json?.updateconfigurationresponse?.configuration || null) }).catch(error => { console.error(error) this.$message.error(this.$t('message.error.save.setting')) diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js index 306eb9d1f59..729cef84d02 100644 --- a/ui/src/utils/plugins.js +++ b/ui/src/utils/plugins.js @@ -550,6 +550,17 @@ export const dialogUtilPlugin = { onOk: () => callback(configRecord) }) } + + app.config.globalProperties.$notifyConfigurationValueChange = function (configRecord) { + if (!configRecord || configRecord.isdynamic || store.getters.userInfo?.roletype !== 'Admin') { + return + } + const server = configRecord.group === 'Usage Server' ? 'usage' : 'mgmt' + this.$notification.warning({ + message: this.$t('label.status'), + description: this.$t('message.restart.' + server + '.server') + }) + } } } diff --git a/ui/src/views/setting/ConfigurationValue.vue b/ui/src/views/setting/ConfigurationValue.vue index 662e5ef142e..31c0798a717 100644 --- a/ui/src/views/setting/ConfigurationValue.vue +++ b/ui/src/views/setting/ConfigurationValue.vue @@ -299,15 +299,7 @@ export default { this.$emit('change-config', { value: newValue }) this.$store.dispatch('RefreshFeatures') this.$messageConfigSuccess(`${this.$t('message.setting.updated')} ${configrecord.name}`, configrecord) - if (json.updateconfigurationresponse && - json.updateconfigurationresponse.configuration && - !json.updateconfigurationresponse.configuration.isdynamic && - ['Admin'].includes(this.$store.getters.userInfo.roletype)) { - this.$notification.warning({ - message: this.$t('label.status'), - description: this.$t('message.restart.mgmt.server') - }) - } + this.$notifyConfigurationValueChange(json?.updateconfigurationresponse?.configuration || null) }).catch(error => { this.editableValue = this.actualValue console.error(error) @@ -341,15 +333,7 @@ export default { this.$emit('change-config', { value: newValue }) this.$store.dispatch('RefreshFeatures') this.$messageConfigSuccess(`${this.$t('label.setting')} ${configrecord.name} ${this.$t('label.reset.config.value')}`, configrecord) - if (json.resetconfigurationresponse && - json.resetconfigurationresponse.configuration && - !json.resetconfigurationresponse.configuration.isdynamic && - ['Admin'].includes(this.$store.getters.userInfo.roletype)) { - this.$notification.warning({ - message: this.$t('label.status'), - description: this.$t('message.restart.mgmt.server') - }) - } + this.$notifyConfigurationValueChange(json?.resetconfigurationresponse?.configuration || null) }).catch(error => { this.editableValue = this.actualValue console.error(error) From 2bfc9cb8eb621cead6b6c8067a878126f1b0c7b5 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 28 Jan 2026 06:47:14 +0100 Subject: [PATCH 5/7] CKS: skip default egress policy check for vpc network offerings (#11998) This PR fixes #11995 Steps to reproduce the issue - create a vpc - create a vpc tier with default offering `DefaultIsolatedNetworkOfferingForVpcNetworks` - register CKS ISO - create CKS on the vpc tier expected: succeed actual: failed with error `Kubernetes service has not been configured properly to provision Kubernetes clusters` --- .../cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java index cf4bbce098a..d19470f8bab 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java @@ -477,7 +477,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne logger.warn("Network offering: {} does not have necessary services to provision Kubernetes cluster", networkOffering); return false; } - if (!networkOffering.isEgressDefaultPolicy()) { + if (!networkOffering.isForVpc() && !networkOffering.isEgressDefaultPolicy()) { logger.warn("Network offering: {} has egress default policy turned off should be on to provision Kubernetes cluster", networkOffering); return false; } From 70d4c9d1baa5f6e7696b6311e7eeaaa2c4f0de3b Mon Sep 17 00:00:00 2001 From: Fabricio Duarte Date: Wed, 28 Jan 2026 02:48:31 -0300 Subject: [PATCH 6/7] Consider secondary storage selectors during cold volume migration (#10957) The secondary storage selectors allow operators to specify, for instance, that volumes should go to a specific secondary storage A. Thus, when uploading a volume, it will always be downloaded to secondary storage A. The cold volume migration moves volumes to a secondary storage before moving them to the destination primary storage. This process does not consider the secondary storage selectors. However, some companies want to dedicate specific secondary storages for cold migration. To address this, this PR makes the cold volume migration process consider the secondary storage selectors. --- .../motion/AncientDataMotionStrategy.java | 13 ++++++++++++- .../storage/heuristics/HeuristicRuleHelper.java | 16 ++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index b59ee2c6166..4cb09fb81f7 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -45,10 +45,12 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.secstorage.heuristics.HeuristicType; import org.apache.cloudstack.storage.RemoteHostEndPoint; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; +import org.apache.cloudstack.storage.heuristics.HeuristicRuleHelper; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.logging.log4j.Logger; @@ -104,6 +106,9 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { @Inject SnapshotDao snapshotDao; + @Inject + HeuristicRuleHelper heuristicRuleHelper; + @Override public StrategyPriority canHandle(DataObject srcData, DataObject destData) { return StrategyPriority.DEFAULT; @@ -374,7 +379,13 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } // need to find a nfs or cifs image store, assuming that can't copy volume // directly to s3 - ImageStoreEntity imageStore = (ImageStoreEntity)dataStoreMgr.getImageStoreWithFreeCapacity(destScope.getScopeId()); + Long zoneId = destScope.getScopeId(); + ImageStoreEntity imageStore = (ImageStoreEntity) heuristicRuleHelper.getImageStoreIfThereIsHeuristicRule(zoneId, HeuristicType.VOLUME, destData); + if (imageStore == null) { + logger.debug("Secondary storage selector did not direct volume migration to a specific secondary storage; using secondary storage with the most free capacity."); + imageStore = (ImageStoreEntity) dataStoreMgr.getImageStoreWithFreeCapacity(zoneId); + } + if (imageStore == null || !imageStore.getProtocol().equalsIgnoreCase("nfs") && !imageStore.getProtocol().equalsIgnoreCase("cifs")) { String errMsg = "can't find a nfs (or cifs) image store to satisfy the need for a staging store"; Answer answer = new Answer(null, false, errMsg); diff --git a/server/src/main/java/org/apache/cloudstack/storage/heuristics/HeuristicRuleHelper.java b/server/src/main/java/org/apache/cloudstack/storage/heuristics/HeuristicRuleHelper.java index 21a34de0d23..2e0780e7fe8 100644 --- a/server/src/main/java/org/apache/cloudstack/storage/heuristics/HeuristicRuleHelper.java +++ b/server/src/main/java/org/apache/cloudstack/storage/heuristics/HeuristicRuleHelper.java @@ -117,8 +117,8 @@ public class HeuristicRuleHelper { accountId = ((SnapshotInfo) obj).getAccountId(); break; case VOLUME: - presetVariables.setVolume(setVolumePresetVariable((VolumeVO) obj)); - accountId = ((VolumeVO) obj).getAccountId(); + presetVariables.setVolume(setVolumePresetVariable((com.cloud.storage.Volume) obj)); + accountId = ((com.cloud.storage.Volume) obj).getAccountId(); break; } presetVariables.setAccount(setAccountPresetVariable(accountId)); @@ -191,14 +191,14 @@ public class HeuristicRuleHelper { return template; } - protected Volume setVolumePresetVariable(VolumeVO volumeVO) { - Volume volume = new Volume(); + protected Volume setVolumePresetVariable(com.cloud.storage.Volume volumeVO) { + Volume volumePresetVariable = new Volume(); - volume.setName(volumeVO.getName()); - volume.setFormat(volumeVO.getFormat()); - volume.setSize(volumeVO.getSize()); + volumePresetVariable.setName(volumeVO.getName()); + volumePresetVariable.setFormat(volumeVO.getFormat()); + volumePresetVariable.setSize(volumeVO.getSize()); - return volume; + return volumePresetVariable; } protected Snapshot setSnapshotPresetVariable(SnapshotInfo snapshotInfo) { From 4761935145e100622df083dedffec612482b16d2 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 28 Jan 2026 06:59:31 +0100 Subject: [PATCH 7/7] server: add options for kvm.guest.os.machine.type (#12414) --- server/src/main/java/com/cloud/api/query/QueryManagerImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 3b232948395..d42dbaec6de 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -5398,6 +5398,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q options.put(VmDetailConstants.VIRTUAL_TPM_VERSION, Arrays.asList("1.2", "2.0")); options.put(VmDetailConstants.GUEST_CPU_MODE, Arrays.asList("custom", "host-model", "host-passthrough")); options.put(VmDetailConstants.GUEST_CPU_MODEL, Collections.emptyList()); + options.put(VmDetailConstants.KVM_GUEST_OS_MACHINE_TYPE, Collections.emptyList()); options.put(VmDetailConstants.KVM_SKIP_FORCE_DISK_CONTROLLER, Arrays.asList("true", "false")); }