From 3ae4bcf4c1a02ae656b7e71fe142fa237300d9fa Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 29 Jul 2025 14:17:32 +0530 Subject: [PATCH 1/6] api,server: allow configuring repetitive alerts Fixes #6613 Introduces support for configuring additional alert types that can be published repeatedly, beyond the default set. Operators can now use the dynamic configuration `alert.allowed.repetitive.types` to specify a comma-separated list of alert type names that should be allowed for repetitive publication. Signed-off-by: Abhishek Kumar --- .../apache/cloudstack/alert/AlertService.java | 92 +++++++++++-------- .../apache/cloudstack/api/ApiConstants.java | 1 + .../admin/resource/ListAlertTypesCmd.java | 12 ++- .../api/response/AlertTypeResponse.java | 12 ++- .../java/com/cloud/alert/AlertManager.java | 20 ++-- .../com/cloud/alert/AlertManagerImpl.java | 62 +++++++++---- 6 files changed, 124 insertions(+), 75 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java index 5146e5c38e8e..d37a07d25ca3 100644 --- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java @@ -16,7 +16,9 @@ // under the License. package org.apache.cloudstack.alert; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import com.cloud.capacity.Capacity; @@ -25,55 +27,59 @@ public interface AlertService { public static class AlertType { private static Set defaultAlertTypes = new HashSet(); + private static Map allAlertTypesMap = new HashMap<>(); private final String name; private final short type; + private final boolean repetitionAllowed; - private AlertType(short type, String name, boolean isDefault) { + private AlertType(short type, String name, boolean isDefault, boolean repetitionAllowed) { this.name = name; this.type = type; + this.repetitionAllowed = repetitionAllowed; if (isDefault) { defaultAlertTypes.add(this); } + allAlertTypesMap.put(name, this); } - public static final AlertType ALERT_TYPE_MEMORY = new AlertType(Capacity.CAPACITY_TYPE_MEMORY, "ALERT.MEMORY", true); - public static final AlertType ALERT_TYPE_CPU = new AlertType(Capacity.CAPACITY_TYPE_CPU, "ALERT.CPU", true); - public static final AlertType ALERT_TYPE_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_STORAGE, "ALERT.STORAGE", true); - public static final AlertType ALERT_TYPE_STORAGE_ALLOCATED = new AlertType(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, "ALERT.STORAGE.ALLOCATED", true); + public static final AlertType ALERT_TYPE_MEMORY = new AlertType(Capacity.CAPACITY_TYPE_MEMORY, "ALERT.MEMORY", true, false); + public static final AlertType ALERT_TYPE_CPU = new AlertType(Capacity.CAPACITY_TYPE_CPU, "ALERT.CPU", true, false); + public static final AlertType ALERT_TYPE_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_STORAGE, "ALERT.STORAGE", true, false); + public static final AlertType ALERT_TYPE_STORAGE_ALLOCATED = new AlertType(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, "ALERT.STORAGE.ALLOCATED", true, false); public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP, "ALERT.NETWORK.PUBLICIP", - true); - public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "ALERT.NETWORK.IPV6SUBNET", true); - public static final AlertType ALERT_TYPE_PRIVATE_IP = new AlertType(Capacity.CAPACITY_TYPE_PRIVATE_IP, "ALERT.NETWORK.PRIVATEIP", true); - public static final AlertType ALERT_TYPE_SECONDARY_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE, "ALERT.STORAGE.SECONDARY", true); - public static final AlertType ALERT_TYPE_HOST = new AlertType((short)7, "ALERT.COMPUTE.HOST", true); - public static final AlertType ALERT_TYPE_USERVM = new AlertType((short)8, "ALERT.USERVM", true); - public static final AlertType ALERT_TYPE_DOMAIN_ROUTER = new AlertType((short)9, "ALERT.SERVICE.DOMAINROUTER", true); - public static final AlertType ALERT_TYPE_CONSOLE_PROXY = new AlertType((short)10, "ALERT.SERVICE.CONSOLEPROXY", true); - public static final AlertType ALERT_TYPE_ROUTING = new AlertType((short)11, "ALERT.NETWORK.ROUTING", true); - public static final AlertType ALERT_TYPE_STORAGE_MISC = new AlertType((short)12, "ALERT.STORAGE.MISC", true); - public static final AlertType ALERT_TYPE_USAGE_SERVER = new AlertType((short)13, "ALERT.USAGE", true); - public static final AlertType ALERT_TYPE_MANAGEMENT_NODE = new AlertType((short)14, "ALERT.MANAGEMENT", true); - public static final AlertType ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = new AlertType((short)15, "ALERT.NETWORK.DOMAINROUTERMIGRATE", true); - public static final AlertType ALERT_TYPE_CONSOLE_PROXY_MIGRATE = new AlertType((short)16, "ALERT.SERVICE.CONSOLEPROXYMIGRATE", true); - public static final AlertType ALERT_TYPE_USERVM_MIGRATE = new AlertType((short)17, "ALERT.USERVM.MIGRATE", true); - public static final AlertType ALERT_TYPE_VLAN = new AlertType((short)18, "ALERT.NETWORK.VLAN", true); - public static final AlertType ALERT_TYPE_SSVM = new AlertType((short)19, "ALERT.SERVICE.SSVM", true); - public static final AlertType ALERT_TYPE_USAGE_SERVER_RESULT = new AlertType((short)20, "ALERT.USAGE.RESULT", true); - public static final AlertType ALERT_TYPE_STORAGE_DELETE = new AlertType((short)21, "ALERT.STORAGE.DELETE", true); - public static final AlertType ALERT_TYPE_UPDATE_RESOURCE_COUNT = new AlertType((short)22, "ALERT.RESOURCE.COUNT", true); - public static final AlertType ALERT_TYPE_USAGE_SANITY_RESULT = new AlertType((short)23, "ALERT.USAGE.SANITY", true); - public static final AlertType ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = new AlertType((short)24, "ALERT.NETWORK.DIRECTPUBLICIP", true); - public static final AlertType ALERT_TYPE_LOCAL_STORAGE = new AlertType((short)25, "ALERT.STORAGE.LOCAL", true); - public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true); - public static final AlertType ALERT_TYPE_SYNC = new AlertType((short)27, "ALERT.TYPE.SYNC", true); - public static final AlertType ALERT_TYPE_UPLOAD_FAILED = new AlertType((short)28, "ALERT.UPLOAD.FAILED", true); - public static final AlertType ALERT_TYPE_OOBM_AUTH_ERROR = new AlertType((short)29, "ALERT.OOBM.AUTHERROR", true); - public static final AlertType ALERT_TYPE_HA_ACTION = new AlertType((short)30, "ALERT.HA.ACTION", true); - public static final AlertType ALERT_TYPE_CA_CERT = new AlertType((short)31, "ALERT.CA.CERT", true); - public static final AlertType ALERT_TYPE_VM_SNAPSHOT = new AlertType((short)32, "ALERT.VM.SNAPSHOT", true); - public static final AlertType ALERT_TYPE_VR_PUBLIC_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PUBLIC.IFACE.MTU", true); - public static final AlertType ALERT_TYPE_VR_PRIVATE_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PRIVATE.IFACE.MTU", true); - public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", true); + true, false); + public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "ALERT.NETWORK.IPV6SUBNET", true, false); + public static final AlertType ALERT_TYPE_PRIVATE_IP = new AlertType(Capacity.CAPACITY_TYPE_PRIVATE_IP, "ALERT.NETWORK.PRIVATEIP", true, false); + public static final AlertType ALERT_TYPE_SECONDARY_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE, "ALERT.STORAGE.SECONDARY", true, false); + public static final AlertType ALERT_TYPE_HOST = new AlertType((short)7, "ALERT.COMPUTE.HOST", true, true); + public static final AlertType ALERT_TYPE_USERVM = new AlertType((short)8, "ALERT.USERVM", true, true); + public static final AlertType ALERT_TYPE_DOMAIN_ROUTER = new AlertType((short)9, "ALERT.SERVICE.DOMAINROUTER", true, true); + public static final AlertType ALERT_TYPE_CONSOLE_PROXY = new AlertType((short)10, "ALERT.SERVICE.CONSOLEPROXY", true, true); + public static final AlertType ALERT_TYPE_ROUTING = new AlertType((short)11, "ALERT.NETWORK.ROUTING", true, false); + public static final AlertType ALERT_TYPE_STORAGE_MISC = new AlertType((short)12, "ALERT.STORAGE.MISC", true, true); + public static final AlertType ALERT_TYPE_USAGE_SERVER = new AlertType((short)13, "ALERT.USAGE", true, false); + public static final AlertType ALERT_TYPE_MANAGEMENT_NODE = new AlertType((short)14, "ALERT.MANAGEMENT", true, true); + public static final AlertType ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = new AlertType((short)15, "ALERT.NETWORK.DOMAINROUTERMIGRATE", true, false); + public static final AlertType ALERT_TYPE_CONSOLE_PROXY_MIGRATE = new AlertType((short)16, "ALERT.SERVICE.CONSOLEPROXYMIGRATE", true, false); + public static final AlertType ALERT_TYPE_USERVM_MIGRATE = new AlertType((short)17, "ALERT.USERVM.MIGRATE", true, false); + public static final AlertType ALERT_TYPE_VLAN = new AlertType((short)18, "ALERT.NETWORK.VLAN", true, false); + public static final AlertType ALERT_TYPE_SSVM = new AlertType((short)19, "ALERT.SERVICE.SSVM", true, true); + public static final AlertType ALERT_TYPE_USAGE_SERVER_RESULT = new AlertType((short)20, "ALERT.USAGE.RESULT", true, false); + public static final AlertType ALERT_TYPE_STORAGE_DELETE = new AlertType((short)21, "ALERT.STORAGE.DELETE", true, false); + public static final AlertType ALERT_TYPE_UPDATE_RESOURCE_COUNT = new AlertType((short)22, "ALERT.RESOURCE.COUNT", true, false); + public static final AlertType ALERT_TYPE_USAGE_SANITY_RESULT = new AlertType((short)23, "ALERT.USAGE.SANITY", true, false); + public static final AlertType ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = new AlertType((short)24, "ALERT.NETWORK.DIRECTPUBLICIP", true, false); + public static final AlertType ALERT_TYPE_LOCAL_STORAGE = new AlertType((short)25, "ALERT.STORAGE.LOCAL", true, false); + public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true, true); + public static final AlertType ALERT_TYPE_SYNC = new AlertType((short)27, "ALERT.TYPE.SYNC", true, false); + public static final AlertType ALERT_TYPE_UPLOAD_FAILED = new AlertType((short)28, "ALERT.UPLOAD.FAILED", true, true); + public static final AlertType ALERT_TYPE_OOBM_AUTH_ERROR = new AlertType((short)29, "ALERT.OOBM.AUTHERROR", true, true); + public static final AlertType ALERT_TYPE_HA_ACTION = new AlertType((short)30, "ALERT.HA.ACTION", true, true); + public static final AlertType ALERT_TYPE_CA_CERT = new AlertType((short)31, "ALERT.CA.CERT", true, true); + public static final AlertType ALERT_TYPE_VM_SNAPSHOT = new AlertType((short)32, "ALERT.VM.SNAPSHOT", true, false); + public static final AlertType ALERT_TYPE_VR_PUBLIC_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PUBLIC.IFACE.MTU", true, false); + public static final AlertType ALERT_TYPE_VR_PRIVATE_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PRIVATE.IFACE.MTU", true, false); + public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", true, true); public short getType() { return type; @@ -83,6 +89,10 @@ public String getName() { return name; } + public boolean isRepetitionAllowed() { + return repetitionAllowed; + } + private static AlertType getAlertType(short type) { for (AlertType alertType : defaultAlertTypes) { if (alertType.getType() == type) { @@ -106,9 +116,13 @@ public static AlertType generateAlert(short type, String name) { if (defaultAlert != null && !defaultAlert.getName().equalsIgnoreCase(name)) { throw new InvalidParameterValueException("There is a default alert having type " + type + " and name " + defaultAlert.getName()); } else { - return new AlertType(type, name, false); + return new AlertType(type, name, false, false); } } + + public static AlertType getAlertTypeByName(String name) { + return allAlertTypesMap.get(name); + } } boolean generateAlert(AlertType alertType, long dataCenterId, Long podId, String msg); diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 00382b76f321..1a267c318799 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -469,6 +469,7 @@ public class ApiConstants { public static final String RECONNECT = "reconnect"; public static final String RECOVER = "recover"; public static final String REPAIR = "repair"; + public static final String REPETITION_ALLOWED = "repetitionallowed"; public static final String REQUIRES_HVM = "requireshvm"; public static final String RESOURCES = "resources"; public static final String RESOURCE_COUNT = "resourcecount"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java index e7bfbdbc6254..dcd4f2c89ef2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java @@ -16,7 +16,10 @@ // under the License. package org.apache.cloudstack.api.command.admin.resource; -import com.cloud.user.Account; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; @@ -24,9 +27,7 @@ import org.apache.cloudstack.api.response.AlertTypeResponse; import org.apache.cloudstack.api.response.ListResponse; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import com.cloud.user.Account; @APICommand(name = "listAlertTypes", description = "Lists all alerts types", responseObject = AlertResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -43,7 +44,8 @@ public void execute() { ListResponse response = new ListResponse<>(); List typeResponseList = new ArrayList<>(); for (AlertService.AlertType alertType : result) { - AlertTypeResponse alertResponse = new AlertTypeResponse(alertType.getType(), alertType.getName()); + AlertTypeResponse alertResponse = new AlertTypeResponse(alertType.getType(), alertType.getName(), + alertType.isRepetitionAllowed()); alertResponse.setObjectName("alerttype"); typeResponseList.add(alertResponse); } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java index 3f91cde01788..e8c3cf6c4ac7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java @@ -16,11 +16,12 @@ // under the License. package org.apache.cloudstack.api.response; -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + public class AlertTypeResponse extends BaseResponse { @SerializedName("alerttypeid") @@ -31,6 +32,10 @@ public class AlertTypeResponse extends BaseResponse { @Param(description = "description of alert type") private String name; + @SerializedName(ApiConstants.REPETITION_ALLOWED) + @Param(description = "Whether repetitive alerts allowed for the alert type", since = "4.22.0") + private boolean repetitionAllowed = true; + public String getName() { return name; } @@ -47,9 +52,10 @@ public void setUsageType(short alertType) { this.alertType = alertType; } - public AlertTypeResponse(short alertType, String name) { + public AlertTypeResponse(short alertType, String name, boolean repetitionAllowed) { this.alertType = alertType; this.name = name; + this.repetitionAllowed = repetitionAllowed; setObjectName("alerttype"); } } diff --git a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java index 3d4e6579f7ca..108bc476fe6e 100644 --- a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java +++ b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java @@ -23,32 +23,36 @@ public interface AlertManager extends Manager, AlertService { - static final ConfigKey StorageCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75", + ConfigKey StorageCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null); - static final ConfigKey CPUCapacityThreshold = new ConfigKey(Double.class, "cluster.cpu.allocated.capacity.notificationthreshold", "Alert", "0.75", + ConfigKey CPUCapacityThreshold = new ConfigKey(Double.class, "cluster.cpu.allocated.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of cpu utilization above which alerts will be sent about low cpu available.", true, ConfigKey.Scope.Cluster, null); - static final ConfigKey MemoryCapacityThreshold = new ConfigKey(Double.class, "cluster.memory.allocated.capacity.notificationthreshold", "Alert", + ConfigKey MemoryCapacityThreshold = new ConfigKey(Double.class, "cluster.memory.allocated.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of memory utilization above which alerts will be sent about low memory available.", true, ConfigKey.Scope.Cluster, null); - static final ConfigKey StorageAllocatedCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.allocated.capacity.notificationthreshold", + ConfigKey StorageAllocatedCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.allocated.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of allocated storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null); - public static final ConfigKey AlertSmtpUseStartTLS = new ConfigKey("Advanced", Boolean.class, "alert.smtp.useStartTLS", "false", + ConfigKey AlertSmtpUseStartTLS = new ConfigKey("Advanced", Boolean.class, "alert.smtp.useStartTLS", "false", "If set to true and if we enable security via alert.smtp.useAuth, this will enable StartTLS to secure the connection.", true); - public static final ConfigKey AlertSmtpUseAuth = new ConfigKey<>(ConfigKey.CATEGORY_ALERT, Boolean.class, "alert.smtp.useAuth", "false", "If true, use SMTP authentication when sending emails.", false, ConfigKey.Scope.ManagementServer); + ConfigKey AlertSmtpUseAuth = new ConfigKey<>(ConfigKey.CATEGORY_ALERT, Boolean.class, "alert.smtp.useAuth", "false", "If true, use SMTP authentication when sending emails.", false, ConfigKey.Scope.ManagementServer); - public static final ConfigKey AlertSmtpEnabledSecurityProtocols = new ConfigKey(ConfigKey.CATEGORY_ADVANCED, String.class, "alert.smtp.enabledSecurityProtocols", "", + ConfigKey AlertSmtpEnabledSecurityProtocols = new ConfigKey(ConfigKey.CATEGORY_ADVANCED, String.class, "alert.smtp.enabledSecurityProtocols", "", "White-space separated security protocols; ex: \"TLSv1 TLSv1.1\". Supported protocols: SSLv2Hello, SSLv3, TLSv1, TLSv1.1 and TLSv1.2", true, ConfigKey.Kind.WhitespaceSeparatedListWithOptions, "SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2"); - public static final ConfigKey Ipv6SubnetCapacityThreshold = new ConfigKey("Advanced", Double.class, + ConfigKey Ipv6SubnetCapacityThreshold = new ConfigKey("Advanced", Double.class, "zone.virtualnetwork.ipv6subnet.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of guest network IPv6 subnet utilization above which alerts will be sent.", true); + ConfigKey AllowedRepetitiveAlertTypes = new ConfigKey<>(ConfigKey.CATEGORY_ALERT, String.class, + "alert.allowed.repetitive.types", "", + "Comma-separated list of alert types (by name) that can be sent multiple times", true); + void clearAlert(AlertType alertType, long dataCenterId, long podId); void recalculateCapacity(); diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java index 3240bfcc8ab6..2393af15b128 100644 --- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java @@ -19,7 +19,6 @@ import java.io.UnsupportedEncodingException; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -41,6 +40,7 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -87,6 +87,7 @@ import com.cloud.resource.ResourceManager; import com.cloud.storage.StorageManager; import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; @@ -97,20 +98,6 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Configurable { protected Logger logger = LogManager.getLogger(AlertManagerImpl.class.getName()); - public static final List ALERTS = Arrays.asList(AlertType.ALERT_TYPE_HOST - , AlertType.ALERT_TYPE_USERVM - , AlertType.ALERT_TYPE_DOMAIN_ROUTER - , AlertType.ALERT_TYPE_CONSOLE_PROXY - , AlertType.ALERT_TYPE_SSVM - , AlertType.ALERT_TYPE_STORAGE_MISC - , AlertType.ALERT_TYPE_MANAGEMENT_NODE - , AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED - , AlertType.ALERT_TYPE_UPLOAD_FAILED - , AlertType.ALERT_TYPE_OOBM_AUTH_ERROR - , AlertType.ALERT_TYPE_HA_ACTION - , AlertType.ALERT_TYPE_CA_CERT - , AlertType.ALERT_TYPE_EXTENSION_PATH_NOT_READY); - private static final long INITIAL_CAPACITY_CHECK_DELAY = 30L * 1000L; // Thirty seconds expressed in milliseconds. private static final DecimalFormat DfPct = new DecimalFormat("###.##"); @@ -148,6 +135,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi Ipv6Service ipv6Service; @Inject HostDao hostDao; + @Inject + MessageBus messageBus; private Timer _timer = null; private long _capacityCheckPeriod = 60L * 60L * 1000L; // One hour by default. @@ -165,6 +154,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi protected String[] recipients = null; protected String senderAddress = null; + private final List allowedRepetitiveAlertTypes = new ArrayList<>(); + public AlertManagerImpl() { _executor = Executors.newCachedThreadPool(new NamedThreadFactory("Email-Alerts-Sender")); } @@ -234,12 +225,31 @@ public boolean configure(String name, Map params) throws Configu _capacityCheckPeriod = Long.parseLong(Config.CapacityCheckPeriod.getDefaultValue()); } } + initMessageBusListener(); + setupRepetitiveAlertTypes(); _timer = new Timer("CapacityChecker"); return true; } + private void setupRepetitiveAlertTypes() { + allowedRepetitiveAlertTypes.clear(); + String allowedRepetitiveAlertsStr = AllowedRepetitiveAlertTypes.value(); + logger.trace("Allowed repetitive alert types specified by {}: {} ", AllowedRepetitiveAlertTypes.key(), + allowedRepetitiveAlertsStr); + String[] allowedRepetitiveAlertTypesArray = allowedRepetitiveAlertsStr.split(","); + for (String alertTypeName : allowedRepetitiveAlertTypesArray) { + AlertType type = AlertType.getAlertTypeByName(alertTypeName); + if (type == null) { + logger.warn("Unknown alert type name: {}, skipping it.", alertTypeName); + continue; + } + allowedRepetitiveAlertTypes.add(type); + } + logger.trace("{} alert types specified for repetitive alerts", allowedRepetitiveAlertTypes.size()); + } + @Override public boolean start() { _timer.schedule(new CapacityChecker(), INITIAL_CAPACITY_CHECK_DELAY, _capacityCheckPeriod); @@ -817,11 +827,10 @@ public void sendAlert(AlertType alertType, DataCenter dataCenter, Pod pod, Clust @Nullable private AlertVO getAlertForTrivialAlertType(AlertType alertType, long dataCenterId, Long podId, Long clusterId) { - AlertVO alert = null; - if (!ALERTS.contains(alertType)) { - alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId); + if (alertType.isRepetitionAllowed() || allowedRepetitiveAlertTypes.contains(alertType)) { + return null; } - return alert; + return _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId); } protected void sendMessage(SMTPMailProperties mailProps) { @@ -850,7 +859,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {CPUCapacityThreshold, MemoryCapacityThreshold, StorageAllocatedCapacityThreshold, StorageCapacityThreshold, AlertSmtpEnabledSecurityProtocols, - AlertSmtpUseStartTLS, Ipv6SubnetCapacityThreshold, AlertSmtpUseAuth}; + AlertSmtpUseStartTLS, Ipv6SubnetCapacityThreshold, AlertSmtpUseAuth, AllowedRepetitiveAlertTypes}; } @Override @@ -864,4 +873,17 @@ public boolean generateAlert(AlertType alertType, long dataCenterId, Long podId, return false; } } + + @SuppressWarnings("unchecked") + private void initMessageBusListener() { + messageBus.subscribe(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, (senderAddress, subject, args) -> { + Ternary updatedSetting = (Ternary) args; + String updatedSettingName = updatedSetting.first(); + if (!AllowedRepetitiveAlertTypes.key().equals(updatedSettingName)) { + return; + + } + setupRepetitiveAlertTypes(); + }); + } } From c3eb733f7351396b256083aef98251af214b84f1 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 30 Jul 2025 16:28:53 +0530 Subject: [PATCH 2/6] add tests Signed-off-by: Abhishek Kumar --- .../com/cloud/alert/AlertManagerImpl.java | 11 ++- .../com/cloud/alert/AlertManagerImplTest.java | 82 +++++++++++++++++++ 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java index 2393af15b128..05971e0b40cf 100644 --- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java @@ -48,6 +48,7 @@ import org.apache.cloudstack.utils.mailing.SMTPMailProperties; import org.apache.cloudstack.utils.mailing.SMTPMailSender; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -233,14 +234,17 @@ public boolean configure(String name, Map params) throws Configu return true; } - private void setupRepetitiveAlertTypes() { + protected void setupRepetitiveAlertTypes() { allowedRepetitiveAlertTypes.clear(); String allowedRepetitiveAlertsStr = AllowedRepetitiveAlertTypes.value(); logger.trace("Allowed repetitive alert types specified by {}: {} ", AllowedRepetitiveAlertTypes.key(), allowedRepetitiveAlertsStr); + if (StringUtils.isBlank(allowedRepetitiveAlertsStr)) { + return; + } String[] allowedRepetitiveAlertTypesArray = allowedRepetitiveAlertsStr.split(","); for (String alertTypeName : allowedRepetitiveAlertTypesArray) { - AlertType type = AlertType.getAlertTypeByName(alertTypeName); + AlertType type = AlertType.getAlertTypeByName(alertTypeName.trim()); if (type == null) { logger.warn("Unknown alert type name: {}, skipping it.", alertTypeName); continue; @@ -875,13 +879,12 @@ public boolean generateAlert(AlertType alertType, long dataCenterId, Long podId, } @SuppressWarnings("unchecked") - private void initMessageBusListener() { + protected void initMessageBusListener() { messageBus.subscribe(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, (senderAddress, subject, args) -> { Ternary updatedSetting = (Ternary) args; String updatedSettingName = updatedSetting.first(); if (!AllowedRepetitiveAlertTypes.key().equals(updatedSettingName)) { return; - } setupRepetitiveAlertTypes(); }); diff --git a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java index d34d0b5873f2..2b4c76ed1d79 100644 --- a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java +++ b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java @@ -21,6 +21,10 @@ import javax.mail.MessagingException; +import org.apache.cloudstack.alert.AlertService; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.MessageSubscriber; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.mailing.SMTPMailSender; @@ -35,6 +39,7 @@ import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; import com.cloud.alert.dao.AlertDao; import com.cloud.capacity.Capacity; @@ -45,10 +50,12 @@ import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.event.EventTypes; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.storage.StorageManager; +import com.cloud.utils.Ternary; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -219,4 +226,79 @@ public void testRecalculateStorageCapacities() { Mockito.verify(storageManager, Mockito.times(2)).createCapacityEntry(sharedPool, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, 10L); Mockito.verify(storageManager, Mockito.times(1)).createCapacityEntry(nonSharedPool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, 20L); } + + @Test + public void initMessageBusListenerSubscribesToConfigurationEditEvent() { + MessageBus messageBusMock = Mockito.mock(MessageBus.class); + alertManagerImplMock.messageBus = messageBusMock; + alertManagerImplMock.initMessageBusListener(); + Mockito.verify(messageBusMock).subscribe(Mockito.eq(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT), Mockito.any()); + } + + @Test + public void initMessageBusListenerTriggersSetupRepetitiveAlertTypesOnAllowedKeyEdit() { + MessageBus messageBusMock = Mockito.mock(MessageBus.class); + alertManagerImplMock.messageBus = messageBusMock; + alertManagerImplMock.initMessageBusListener(); + ArgumentCaptor captor = ArgumentCaptor.forClass(MessageSubscriber.class); + Mockito.verify(messageBusMock).subscribe(Mockito.eq(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT), captor.capture()); + Ternary args = new Ternary<>(AlertManager.AllowedRepetitiveAlertTypes.key(), ConfigKey.Scope.Global, 1L); + captor.getValue().onPublishMessage(null, null, args); + Mockito.verify(alertManagerImplMock).setupRepetitiveAlertTypes(); + } + + @Test + public void initMessageBusListenerDoesNotTriggerSetupRepetitiveAlertTypesOnOtherKeyEdit() { + MessageBus messageBusMock = Mockito.mock(MessageBus.class); + alertManagerImplMock.messageBus = messageBusMock; + alertManagerImplMock.initMessageBusListener(); + ArgumentCaptor captor = ArgumentCaptor.forClass(MessageSubscriber.class); + Mockito.verify(messageBusMock).subscribe(Mockito.eq(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT), captor.capture()); + Ternary args = new Ternary<>("some.other.key", ConfigKey.Scope.Global, 1L); + captor.getValue().onPublishMessage(null, null, args); + Mockito.verify(alertManagerImplMock, Mockito.never()).setupRepetitiveAlertTypes(); + } + + private void mockAllowedRepetitiveAlertTypesConfigKey(String value) { + ReflectionTestUtils.setField(AlertManager.AllowedRepetitiveAlertTypes, "_defaultValue", value); + } + + @Test + public void setupRepetitiveAlertTypesParsesValidAlertTypesCorrectly() { + mockAllowedRepetitiveAlertTypesConfigKey("ALERT.CPU,ALERT.MEMORY"); + alertManagerImplMock.setupRepetitiveAlertTypes(); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + Assert.assertNotNull(expectedTypes); + Assert.assertEquals(2, expectedTypes.size()); + Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU)); + Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_MEMORY)); + } + + @Test + public void setupRepetitiveAlertTypesHandlesEmptyConfigValue() { + mockAllowedRepetitiveAlertTypesConfigKey(""); + alertManagerImplMock.setupRepetitiveAlertTypes(); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + Assert.assertNotNull(expectedTypes); + Assert.assertTrue(expectedTypes.isEmpty()); + } + + @Test + public void setupRepetitiveAlertTypesIgnoresUnknownAlertTypes() { + mockAllowedRepetitiveAlertTypesConfigKey("ALERT.CPU,UNKNOWN_ALERT_TYPE"); + alertManagerImplMock.setupRepetitiveAlertTypes(); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + Assert.assertNotNull(expectedTypes); + Assert.assertEquals(1, expectedTypes.size()); + Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU)); + } + + @Test + public void setupRepetitiveAlertTypesHandlesNullConfigValue() { + mockAllowedRepetitiveAlertTypesConfigKey(null); + alertManagerImplMock.setupRepetitiveAlertTypes(); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + Assert.assertNotNull(expectedTypes); + Assert.assertTrue(expectedTypes.isEmpty()); + } } From 195e4e5f16d56f9f7c024ad552f300c03914a847 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 30 Jul 2025 17:34:52 +0530 Subject: [PATCH 3/6] fix Signed-off-by: Abhishek Kumar --- .../java/com/cloud/alert/AlertManagerImplTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java index 2b4c76ed1d79..99deb6939480 100644 --- a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java +++ b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java @@ -16,6 +16,12 @@ // under the License. package com.cloud.alert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + import java.io.UnsupportedEncodingException; import java.util.List; @@ -57,12 +63,6 @@ import com.cloud.storage.StorageManager; import com.cloud.utils.Ternary; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - @RunWith(MockitoJUnitRunner.class) public class AlertManagerImplTest { @@ -226,7 +226,7 @@ public void testRecalculateStorageCapacities() { Mockito.verify(storageManager, Mockito.times(2)).createCapacityEntry(sharedPool, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, 10L); Mockito.verify(storageManager, Mockito.times(1)).createCapacityEntry(nonSharedPool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, 20L); } - + @Test public void initMessageBusListenerSubscribesToConfigurationEditEvent() { MessageBus messageBusMock = Mockito.mock(MessageBus.class); From de6ff00a0e38d161c08e66032e1e4b3c6f6dcddc Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 1 Aug 2025 12:20:07 +0530 Subject: [PATCH 4/6] test fix Signed-off-by: Abhishek Kumar --- server/src/test/java/com/cloud/alert/AlertManagerImplTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java index 58f920b9e5cd..68f280da6888 100644 --- a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java +++ b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java @@ -119,6 +119,9 @@ public class AlertManagerImplTest { @Mock ConfigurationDao configDao; + @Mock + MessageBus messageBus; + private final String[] recipients = new String[]{"test@test.com"}; private final String senderAddress = "sender@test.com"; From d8ea50263d0c5ba5af7a3c7b11e4f923f0f541b6 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 1 Aug 2025 15:23:54 +0530 Subject: [PATCH 5/6] allow repetition for custom alerts Signed-off-by: Abhishek Kumar --- .../apache/cloudstack/alert/AlertService.java | 10 +------- .../com/cloud/alert/AlertManagerImpl.java | 24 ++++++++---------- .../com/cloud/alert/AlertManagerImplTest.java | 25 ++++++++++--------- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java index 12d85595cbca..9c327020061b 100644 --- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java @@ -16,9 +16,7 @@ // under the License. package org.apache.cloudstack.alert; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; import com.cloud.capacity.Capacity; @@ -26,8 +24,7 @@ public interface AlertService { public static class AlertType { - private static Set defaultAlertTypes = new HashSet(); - private static Map allAlertTypesMap = new HashMap<>(); + private static final Set defaultAlertTypes = new HashSet<>(); private final String name; private final short type; private final boolean repetitionAllowed; @@ -39,7 +36,6 @@ private AlertType(short type, String name, boolean isDefault, boolean repetition if (isDefault) { defaultAlertTypes.add(this); } - allAlertTypesMap.put(name, this); } public static final AlertType ALERT_TYPE_MEMORY = new AlertType(Capacity.CAPACITY_TYPE_MEMORY, "ALERT.MEMORY", true, false); @@ -120,10 +116,6 @@ public static AlertType generateAlert(short type, String name) { return new AlertType(type, name, false, false); } } - - public static AlertType getAlertTypeByName(String name) { - return allAlertTypesMap.get(name); - } } boolean generateAlert(AlertType alertType, long dataCenterId, Long podId, String msg); diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java index e8c2970055a7..ede251a9d269 100644 --- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java @@ -36,10 +36,6 @@ import javax.mail.MessagingException; import javax.naming.ConfigurationException; -import com.cloud.dc.DataCenter; -import com.cloud.dc.Pod; -import com.cloud.org.Cluster; - import org.apache.cloudstack.backup.BackupManager; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; @@ -71,9 +67,11 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; +import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; @@ -87,6 +85,7 @@ import com.cloud.host.dao.HostDao; import com.cloud.network.Ipv6Service; import com.cloud.network.dao.IPAddressDao; +import com.cloud.org.Cluster; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; import com.cloud.storage.StorageManager; @@ -164,7 +163,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi protected String[] recipients = null; protected String senderAddress = null; - private final List allowedRepetitiveAlertTypes = new ArrayList<>(); + private final List allowedRepetitiveAlertTypeNames = new ArrayList<>(); public AlertManagerImpl() { _executor = Executors.newCachedThreadPool(new NamedThreadFactory("Email-Alerts-Sender")); @@ -254,7 +253,7 @@ public boolean configure(String name, Map params) throws Configu } protected void setupRepetitiveAlertTypes() { - allowedRepetitiveAlertTypes.clear(); + allowedRepetitiveAlertTypeNames.clear(); String allowedRepetitiveAlertsStr = AllowedRepetitiveAlertTypes.value(); logger.trace("Allowed repetitive alert types specified by {}: {} ", AllowedRepetitiveAlertTypes.key(), allowedRepetitiveAlertsStr); @@ -262,15 +261,13 @@ protected void setupRepetitiveAlertTypes() { return; } String[] allowedRepetitiveAlertTypesArray = allowedRepetitiveAlertsStr.split(","); - for (String alertTypeName : allowedRepetitiveAlertTypesArray) { - AlertType type = AlertType.getAlertTypeByName(alertTypeName.trim()); - if (type == null) { - logger.warn("Unknown alert type name: {}, skipping it.", alertTypeName); + for (String allowedTypeName : allowedRepetitiveAlertTypesArray) { + if (StringUtils.isBlank(allowedTypeName)) { continue; } - allowedRepetitiveAlertTypes.add(type); + allowedRepetitiveAlertTypeNames.add(allowedTypeName.toLowerCase()); } - logger.trace("{} alert types specified for repetitive alerts", allowedRepetitiveAlertTypes.size()); + logger.trace("{} alert types specified for repetitive alerts", allowedRepetitiveAlertTypeNames.size()); } @Override @@ -868,7 +865,8 @@ public void sendAlert(AlertType alertType, DataCenter dataCenter, Pod pod, Clust @Nullable private AlertVO getAlertForTrivialAlertType(AlertType alertType, long dataCenterId, Long podId, Long clusterId) { - if (alertType.isRepetitionAllowed() || allowedRepetitiveAlertTypes.contains(alertType)) { + if (alertType.isRepetitionAllowed() || (StringUtils.isNotBlank(alertType.getName()) && + allowedRepetitiveAlertTypeNames.contains(alertType.getName().toLowerCase()))) { return null; } return _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId); diff --git a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java index 68f280da6888..b5932e8a071a 100644 --- a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java +++ b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java @@ -30,7 +30,6 @@ import javax.mail.MessagingException; import javax.naming.ConfigurationException; -import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.backup.BackupManager; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -317,39 +316,41 @@ private void mockAllowedRepetitiveAlertTypesConfigKey(String value) { @Test public void setupRepetitiveAlertTypesParsesValidAlertTypesCorrectly() { - mockAllowedRepetitiveAlertTypesConfigKey("ALERT.CPU,ALERT.MEMORY"); + mockAllowedRepetitiveAlertTypesConfigKey(AlertManager.AlertType.ALERT_TYPE_CPU.getName() + "," + AlertManager.AlertType.ALERT_TYPE_MEMORY.getName()); alertManagerImplMock.setupRepetitiveAlertTypes(); - List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames"); Assert.assertNotNull(expectedTypes); Assert.assertEquals(2, expectedTypes.size()); - Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU)); - Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_MEMORY)); + Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU.getName().toLowerCase())); + Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_MEMORY.getName().toLowerCase())); } @Test public void setupRepetitiveAlertTypesHandlesEmptyConfigValue() { mockAllowedRepetitiveAlertTypesConfigKey(""); alertManagerImplMock.setupRepetitiveAlertTypes(); - List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames"); Assert.assertNotNull(expectedTypes); Assert.assertTrue(expectedTypes.isEmpty()); } @Test - public void setupRepetitiveAlertTypesIgnoresUnknownAlertTypes() { - mockAllowedRepetitiveAlertTypesConfigKey("ALERT.CPU,UNKNOWN_ALERT_TYPE"); + public void setupRepetitiveAlertTypesIgnoresCustomAlertTypes() { + String customAlertTypeName = "CUSTOM_ALERT_TYPE"; + mockAllowedRepetitiveAlertTypesConfigKey(AlertManager.AlertType.ALERT_TYPE_CPU.getName() + "," + customAlertTypeName); alertManagerImplMock.setupRepetitiveAlertTypes(); - List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames"); Assert.assertNotNull(expectedTypes); - Assert.assertEquals(1, expectedTypes.size()); - Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU)); + Assert.assertEquals(2, expectedTypes.size()); + Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU.getName().toLowerCase())); + Assert.assertTrue(expectedTypes.contains(customAlertTypeName.toLowerCase())); } @Test public void setupRepetitiveAlertTypesHandlesNullConfigValue() { mockAllowedRepetitiveAlertTypesConfigKey(null); alertManagerImplMock.setupRepetitiveAlertTypes(); - List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypes"); + List expectedTypes = (List)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames"); Assert.assertNotNull(expectedTypes); Assert.assertTrue(expectedTypes.isEmpty()); } From 0299cfc4f74b561a6668fa10fb93c9ccd4be90ea Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 1 Aug 2025 15:27:50 +0530 Subject: [PATCH 6/6] remove refactoring Signed-off-by: Abhishek Kumar --- .../main/java/com/cloud/alert/AlertManager.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java index 108bc476fe6e..b03d0f91b5c7 100644 --- a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java +++ b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java @@ -23,27 +23,27 @@ public interface AlertManager extends Manager, AlertService { - ConfigKey StorageCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75", + static final ConfigKey StorageCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null); - ConfigKey CPUCapacityThreshold = new ConfigKey(Double.class, "cluster.cpu.allocated.capacity.notificationthreshold", "Alert", "0.75", + static final ConfigKey CPUCapacityThreshold = new ConfigKey(Double.class, "cluster.cpu.allocated.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of cpu utilization above which alerts will be sent about low cpu available.", true, ConfigKey.Scope.Cluster, null); - ConfigKey MemoryCapacityThreshold = new ConfigKey(Double.class, "cluster.memory.allocated.capacity.notificationthreshold", "Alert", + static final ConfigKey MemoryCapacityThreshold = new ConfigKey(Double.class, "cluster.memory.allocated.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of memory utilization above which alerts will be sent about low memory available.", true, ConfigKey.Scope.Cluster, null); - ConfigKey StorageAllocatedCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.allocated.capacity.notificationthreshold", + static final ConfigKey StorageAllocatedCapacityThreshold = new ConfigKey(Double.class, "cluster.storage.allocated.capacity.notificationthreshold", "Alert", "0.75", "Percentage (as a value between 0 and 1) of allocated storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null); - ConfigKey AlertSmtpUseStartTLS = new ConfigKey("Advanced", Boolean.class, "alert.smtp.useStartTLS", "false", + public static final ConfigKey AlertSmtpUseStartTLS = new ConfigKey("Advanced", Boolean.class, "alert.smtp.useStartTLS", "false", "If set to true and if we enable security via alert.smtp.useAuth, this will enable StartTLS to secure the connection.", true); - ConfigKey AlertSmtpUseAuth = new ConfigKey<>(ConfigKey.CATEGORY_ALERT, Boolean.class, "alert.smtp.useAuth", "false", "If true, use SMTP authentication when sending emails.", false, ConfigKey.Scope.ManagementServer); + public static final ConfigKey AlertSmtpUseAuth = new ConfigKey<>(ConfigKey.CATEGORY_ALERT, Boolean.class, "alert.smtp.useAuth", "false", "If true, use SMTP authentication when sending emails.", false, ConfigKey.Scope.ManagementServer); - ConfigKey AlertSmtpEnabledSecurityProtocols = new ConfigKey(ConfigKey.CATEGORY_ADVANCED, String.class, "alert.smtp.enabledSecurityProtocols", "", + public static final ConfigKey AlertSmtpEnabledSecurityProtocols = new ConfigKey(ConfigKey.CATEGORY_ADVANCED, String.class, "alert.smtp.enabledSecurityProtocols", "", "White-space separated security protocols; ex: \"TLSv1 TLSv1.1\". Supported protocols: SSLv2Hello, SSLv3, TLSv1, TLSv1.1 and TLSv1.2", true, ConfigKey.Kind.WhitespaceSeparatedListWithOptions, "SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2"); - ConfigKey Ipv6SubnetCapacityThreshold = new ConfigKey("Advanced", Double.class, + public static final ConfigKey Ipv6SubnetCapacityThreshold = new ConfigKey("Advanced", Double.class, "zone.virtualnetwork.ipv6subnet.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of guest network IPv6 subnet utilization above which alerts will be sent.",