From 4c78cd7ecb96ca7ac8c88a8080c84930608aee30 Mon Sep 17 00:00:00 2001 From: Chinmay Soni Date: Wed, 22 Jul 2026 13:46:44 +0000 Subject: [PATCH 1/2] fix: enforce OOBM validation for KVM HA on UI and backend APIs --- .../admin/ha/ConfigureHAForHostCmd.java | 12 ++++++++++++ .../command/admin/ha/EnableHAForHostCmd.java | 16 +++++++++++++++- .../DisableOutOfBandManagementForHostCmd.java | 19 +++++++++++++++++-- ui/src/config/section/infra/hosts.js | 5 ++++- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java index d7707e197d64..04fe128eb9c2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java @@ -38,6 +38,9 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.ha.HAConfigManager; import org.apache.cloudstack.ha.HAResource; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; +import com.cloud.hypervisor.Hypervisor.HypervisorType; + import javax.inject.Inject; @@ -50,6 +53,9 @@ public final class ConfigureHAForHostCmd extends BaseAsyncCmd { @Inject private HAConfigManager haConfigManager; + @Inject + private OutOfBandManagementService outOfBandManagementService; + ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -98,6 +104,12 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); } + if (host.getHypervisorType() == HypervisorType.KVM) { + if (!outOfBandManagementService.isOutOfBandManagementEnabled(host)) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot configure HA on KVM host because Out-of-Band Management (OOBM) is not enabled."); + } + } + final boolean result = haConfigManager.configureHA(host.getId(), HAResource.ResourceType.Host, getHaProvider()); if (!result) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to configure HA provider for the host"); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java index f54767225432..82a9f6554012 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java @@ -37,7 +37,8 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.ha.HAConfigManager; import org.apache.cloudstack.ha.HAResource; - +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; import javax.inject.Inject; @APICommand(name = "enableHAForHost", description = "Enables HA for a host", @@ -49,6 +50,10 @@ public final class EnableHAForHostCmd extends BaseAsyncCmd { @Inject private HAConfigManager haConfigManager; + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -89,6 +94,15 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE if (host == null) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); } + + // --- YOUR NEW GUARDRAIL --- + if (host.getHypervisorType() == HypervisorType.KVM) { + if (!outOfBandManagementService.isOutOfBandManagementEnabled(host)) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot enable HA on KVM host because Out-of-Band Management (OOBM) is not enabled."); + } + } + // -------------------------- + final boolean result = haConfigManager.enableHA(host.getId(), HAResource.ResourceType.Host); CallContext.current().setEventDetails("Host Id:" + host.getId() + " HA enabled: true"); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java index 6c9b48ef28f7..6ae61b11de8b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java @@ -38,6 +38,9 @@ import org.apache.cloudstack.api.response.OutOfBandManagementResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; +import org.apache.cloudstack.ha.HAConfigManager; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import org.apache.cloudstack.ha.HAResource; import javax.inject.Inject; @@ -46,6 +49,9 @@ since = "4.9.0", authorized = {RoleType.Admin}) public class DisableOutOfBandManagementForHostCmd extends BaseAsyncCmd { + @Inject + private HAConfigManager haConfigManager; + @Inject private OutOfBandManagementService outOfBandManagementService; @@ -61,13 +67,22 @@ public class DisableOutOfBandManagementForHostCmd extends BaseAsyncCmd { /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// - @Override - final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { final Host host = _resourceService.getHost(getHostId()); if (host == null) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); } + if (host.getHypervisorType() == HypervisorType.KVM) { + java.util.List haConfigs = haConfigManager.listHAResources(host.getId(), HAResource.ResourceType.Host); + if (haConfigs != null && !haConfigs.isEmpty()) { + if (haConfigs.get(0).isEnabled()) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot disable Out-of-Band Management (OOBM) because HA is currently enabled on this KVM host. Please disable HA first."); + } + } + } + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(host); CallContext.current().setEventDetails("Host Id:" + host.getId() + " out-of-band management enabled: false"); diff --git a/ui/src/config/section/infra/hosts.js b/ui/src/config/section/infra/hosts.js index f81d19b136df..b89d3b7f589e 100644 --- a/ui/src/config/section/infra/hosts.js +++ b/ui/src/config/section/infra/hosts.js @@ -195,7 +195,10 @@ export default { docHelp: 'adminguide/hosts.html#out-of-band-management', dataView: true, show: (record) => { - return record?.outofbandmanagement?.enabled === true + if (record.hypervisor === 'KVM' && record?.hostha?.haenable === true) { + return false; + } + return record?.outofbandmanagement?.enabled === true; }, args: ['hostid'], mapping: { From eaad0f3b4e44fa4047ac3bede7a41a719003a3f9 Mon Sep 17 00:00:00 2001 From: Chinmay Soni Date: Wed, 22 Jul 2026 13:59:28 +0000 Subject: [PATCH 2/2] fix(ui): remove extra semicolon in hosts.js --- ui/src/config/section/infra/hosts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/config/section/infra/hosts.js b/ui/src/config/section/infra/hosts.js index b89d3b7f589e..dc189d2e25e7 100644 --- a/ui/src/config/section/infra/hosts.js +++ b/ui/src/config/section/infra/hosts.js @@ -196,9 +196,9 @@ export default { dataView: true, show: (record) => { if (record.hypervisor === 'KVM' && record?.hostha?.haenable === true) { - return false; + return false } - return record?.outofbandmanagement?.enabled === true; + return record?.outofbandmanagement?.enabled === true }, args: ['hostid'], mapping: {