AMBARI-6915 - Alerts: Change AlertDefinition to Support a Reporting Member (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0ac9cb3f Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0ac9cb3f Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0ac9cb3f Branch: refs/heads/branch-alerts-dev Commit: 0ac9cb3facaff211c5c679d609f59aaca633d267 Parents: 72ebd26 Author: Jonathan Hurley <jhur...@hortonworks.com> Authored: Tue Aug 19 10:14:30 2014 -0400 Committer: Jonathan Hurley <jhur...@hortonworks.com> Committed: Wed Aug 20 10:54:28 2014 -0400 ---------------------------------------------------------------------- .../server/api/services/AmbariMetaInfo.java | 16 +--- .../AlertDefinitionResourceProvider.java | 63 ++++++++++++-- .../server/state/alert/AggregateSource.java | 38 ++++++++ .../server/state/alert/AlertDefinition.java | 17 ++++ .../state/alert/AlertDefinitionFactory.java | 84 +++++++++++++++--- .../server/state/alert/PercentSource.java | 76 ++++++++++++++++ .../ambari/server/state/alert/PortSource.java | 46 ++++++++++ .../ambari/server/state/alert/Reporting.java | 92 ++++++++++++++++++++ .../ambari/server/state/alert/ScriptSource.java | 36 ++++++++ .../ambari/server/state/alert/Source.java | 13 ++- .../ambari/server/state/alert/SourceType.java | 9 +- .../server/api/services/AmbariMetaInfoTest.java | 51 +++++++++++ .../AlertDefinitionResourceProviderTest.java | 89 +++++++++++++++++-- .../stacks/HDP/2.0.5/services/HDFS/alerts.json | 61 ++++++++----- 14 files changed, 626 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java index 3347a77..2eec33b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java @@ -31,7 +31,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Scanner; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -1093,19 +1092,6 @@ public class AmbariMetaInfo { return null; } - Set<AlertDefinition> defs = new HashSet<AlertDefinition>(); - Map<String, List<AlertDefinition>> map = alertDefinitionFactory.getAlertDefinitions(alertsFile); - - for (Entry<String, List<AlertDefinition>> entry : map.entrySet()) { - for (AlertDefinition ad : entry.getValue()) { - ad.setServiceName(serviceName); - if (!entry.getKey().equals("service")) { - ad.setComponentName(entry.getKey()); - } - } - defs.addAll(entry.getValue()); - } - - return defs; + return alertDefinitionFactory.getAlertDefinitions(alertsFile, serviceName); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java index f20a9a9..bed25e7 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java @@ -61,18 +61,26 @@ import com.google.inject.Injector; */ public class AlertDefinitionResourceProvider extends AbstractControllerResourceProvider { + protected static final String ALERT_DEF = "AlertDefinition"; + protected static final String ALERT_DEF_CLUSTER_NAME = "AlertDefinition/cluster_name"; protected static final String ALERT_DEF_ID = "AlertDefinition/id"; protected static final String ALERT_DEF_NAME = "AlertDefinition/name"; protected static final String ALERT_DEF_LABEL = "AlertDefinition/label"; protected static final String ALERT_DEF_INTERVAL = "AlertDefinition/interval"; - protected static final String ALERT_DEF_SOURCE_TYPE = "AlertDefinition/source/type"; - protected static final String ALERT_DEF_SOURCE = "AlertDefinition/source"; protected static final String ALERT_DEF_SERVICE_NAME = "AlertDefinition/service_name"; protected static final String ALERT_DEF_COMPONENT_NAME = "AlertDefinition/component_name"; protected static final String ALERT_DEF_ENABLED = "AlertDefinition/enabled"; protected static final String ALERT_DEF_SCOPE = "AlertDefinition/scope"; + protected static final String ALERT_DEF_SOURCE = "AlertDefinition/source"; + protected static final String ALERT_DEF_SOURCE_TYPE = "AlertDefinition/source/type"; + protected static final String ALERT_DEF_SOURCE_REPORTING = "AlertDefinition/source/reporting"; + protected static final String ALERT_DEF_SOURCE_REPORTING_OK = "AlertDefinition/source/reporting/ok"; + protected static final String ALERT_DEF_SOURCE_REPORTING_WARNING = "AlertDefinition/source/reporting/warning"; + protected static final String ALERT_DEF_SOURCE_REPORTING_CRITICAL = "AlertDefinition/source/reporting/critical"; + + private static Set<String> pkPropertyIds = new HashSet<String>( Arrays.asList(ALERT_DEF_ID, ALERT_DEF_NAME)); @@ -176,21 +184,64 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP SourceType.class))); } - JsonObject jsonObj = new JsonObject(); + // !!! Alert structures contain nested objects; reconstruct a valid + // JSON from the flat, exploded properties so that a Source instance can + // be properly persisted + JsonObject source = new JsonObject(); + JsonObject reporting = new JsonObject(); + JsonObject reportingOk = new JsonObject(); + JsonObject reportingWarning = new JsonObject(); + JsonObject reportingCritical = new JsonObject(); for (Entry<String, Object> entry : requestMap.entrySet()) { String propCat = PropertyHelper.getPropertyCategory(entry.getKey()); String propName = PropertyHelper.getPropertyName(entry.getKey()); + if (propCat.equals(ALERT_DEF) && "source".equals(propName)) { + source.addProperty(propName, entry.getValue().toString()); + } + if (propCat.equals(ALERT_DEF_SOURCE)) { - jsonObj.addProperty(propName, entry.getValue().toString()); + source.addProperty(propName, entry.getValue().toString()); + } + + if (propCat.equals(ALERT_DEF_SOURCE_REPORTING)) { + reporting.addProperty(propName, entry.getValue().toString()); + } + + if (propCat.equals(ALERT_DEF_SOURCE_REPORTING_OK)) { + reportingOk.addProperty(propName, entry.getValue().toString()); + } + + if (propCat.equals(ALERT_DEF_SOURCE_REPORTING_WARNING)) { + reportingWarning.addProperty(propName, entry.getValue().toString()); + } + + if (propCat.equals(ALERT_DEF_SOURCE_REPORTING_CRITICAL)) { + reportingCritical.addProperty(propName, entry.getValue().toString()); } } - if (0 == jsonObj.entrySet().size()) { + if (0 == source.entrySet().size()) { throw new IllegalArgumentException("Source must be specified"); } + if (reportingOk.entrySet().size() > 0) { + reporting.add("ok", reportingOk); + } + + if (reportingWarning.entrySet().size() > 0) { + reporting.add("warning", reportingWarning); + } + + if (reportingCritical.entrySet().size() > 0) { + reporting.add("critical", reportingCritical); + } + + if (reporting.entrySet().size() > 0) { + source.add("reporting", reporting); + } + Cluster cluster = getManagementController().getClusters().getCluster(clusterName); AlertDefinitionEntity entity = new AlertDefinitionEntity(); @@ -207,7 +258,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP entity.setScheduleInterval(interval); entity.setServiceName((String) requestMap.get(ALERT_DEF_SERVICE_NAME)); entity.setSourceType((String) requestMap.get(ALERT_DEF_SOURCE_TYPE)); - entity.setSource(jsonObj.toString()); + entity.setSource(source.toString()); Scope scope = null; String desiredScope = (String) requestMap.get(ALERT_DEF_SCOPE); http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java new file mode 100644 index 0000000..d056c40 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.state.alert; + +import com.google.gson.annotations.SerializedName; + +/** + * Alert when the source type is defined as {@link SourceType#AGGREGATE}. + * Aggregate alerts are alerts that are triggered by collecting the states of + * all instances of the defined alert and calculating the overall state. + */ +public class AggregateSource extends Source { + + @SerializedName("alert_name") + private String m_alertName = null; + + /** + * @return the unique name of the alert that will have its values aggregated. + */ + public String getAlertName() { + return m_alertName; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java index 8d9b3c2..15f4bfe 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java @@ -31,6 +31,7 @@ public class AlertDefinition { private int interval = 1; private boolean enabled = true; private Source source = null; + private String label = null; /** * @return the service name @@ -117,6 +118,22 @@ public class AlertDefinition { source = definitionSource; } + /** + * @return the label for the definition or {@code null} if none. + */ + public String getLabel() { + return label; + } + + /** + * Sets the label for this definition. + * + * @param definitionLabel + */ + public void setLabel(String definitionLabel) { + label = definitionLabel; + } + @Override public boolean equals(Object obj) { if (null == obj || !obj.getClass().equals(AlertDefinition.class)) { http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java index 1775f88..5ddb521 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java @@ -20,8 +20,11 @@ package org.apache.ambari.server.state.alert; import java.io.File; import java.io.FileReader; import java.lang.reflect.Type; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; @@ -52,34 +55,58 @@ public class AlertDefinitionFactory { /** * Builder used for type adapter registration. */ - private final GsonBuilder m_builder = new GsonBuilder().registerTypeAdapter( - Source.class, new AlertDefinitionSourceAdapter()); + private final GsonBuilder m_builder = new GsonBuilder(); /** * Thread safe deserializer. */ - private final Gson m_gson = m_builder.create(); + private final Gson m_gson; + /** + * Constructor. + */ + public AlertDefinitionFactory() { + m_builder.registerTypeAdapter(Source.class, + new AlertDefinitionSourceAdapter()); + + m_gson = m_builder.create(); + } /** * Gets a list of all of the alert definitions defined in the specified JSON - * {@link File}. + * {@link File} for the given service. * * @param alertDefinitionFile + * @param serviceName * @return * @throws AmbariException * if there was a problem reading the file or parsing the JSON. */ - public Map<String, List<AlertDefinition>> getAlertDefinitions( - File alertDefinitionFile) throws AmbariException { + public Set<AlertDefinition> getAlertDefinitions(File alertDefinitionFile, + String serviceName) throws AmbariException { + Map<String,List<AlertDefinition>> definitionMap = null; + try { Type type = new TypeToken<Map<String, List<AlertDefinition>>>(){}.getType(); - return m_gson.fromJson(new FileReader(alertDefinitionFile), type); + definitionMap = m_gson.fromJson(new FileReader(alertDefinitionFile), type); } catch (Exception e) { LOG.error("Could not read the alert definition file", e); throw new AmbariException("Could not read alert definition file", e); } + + Set<AlertDefinition> definitions = new HashSet<AlertDefinition>(); + for (Entry<String, List<AlertDefinition>> entry : definitionMap.entrySet()) { + for (AlertDefinition ad : entry.getValue()) { + ad.setServiceName(serviceName); + if (!entry.getKey().equals("service")) { + ad.setComponentName(entry.getKey()); + } + } + definitions.addAll(entry.getValue()); + } + + return definitions; } /** @@ -103,6 +130,7 @@ public class AlertDefinitionFactory { definition.setName(entity.getDefinitionName()); definition.setScope(entity.getScope()); definition.setServiceName(entity.getServiceName()); + definition.setLabel(entity.getLabel()); try{ String sourceJson = entity.getSource(); @@ -118,6 +146,16 @@ public class AlertDefinitionFactory { } /** + * Gets an instance of {@link Gson} that can correctly serialize and + * deserialize an {@link AlertDefinition}. + * + * @return a {@link Gson} instance (not {@code null}). + */ + public Gson getGson() { + return m_gson; + } + + /** * Deserializes {@link Source} implementations. */ private static final class AlertDefinitionSourceAdapter implements JsonDeserializer<Source>{ @@ -130,21 +168,41 @@ public class AlertDefinitionFactory { JsonObject jsonObj = (JsonObject) json; SourceType type = SourceType.valueOf(jsonObj.get("type").getAsString()); - Class<? extends Source> cls = null; + Class<? extends Source> clazz = null; switch (type) { - case METRIC: - cls = MetricSource.class; + case METRIC:{ + clazz = MetricSource.class; + break; + } + case PORT:{ + clazz = PortSource.class; break; + } + case SCRIPT: { + clazz = ScriptSource.class; + break; + } + case AGGREGATE: { + clazz = AggregateSource.class; + break; + } + case PERCENT: { + clazz = PercentSource.class; + break; + } default: break; } - if (null != cls) { - return context.deserialize(json, cls); - } else { + if (null == clazz) { + LOG.warn( + "Unable to deserialize an alert definition with source type {}", + type); return null; } + + return context.deserialize(json, clazz); } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java new file mode 100644 index 0000000..ef79cfd --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.state.alert; + +import com.google.gson.annotations.SerializedName; + +/** + * Alert when the source type is defined as {@link SourceType#PERCENT} + */ +public class PercentSource extends Source { + + @SerializedName("numerator") + private MetricFractionPart m_numerator = null; + + @SerializedName("denominator") + private MetricFractionPart m_denominator = null; + + /** + * Gets the numerator for the percent calculation. + * + * @return a metric value representing the numerator (never {@code null}). + */ + public MetricFractionPart getNumerator() { + return m_numerator; + } + + /** + * Gets the denomintor for the percent calculation. + * + * @return a metric value representing the denominator (never {@code null}). + */ + public MetricFractionPart getDenominator() { + return m_denominator; + } + + /** + * The {@link MetricFractionPart} class represents either the numerator or the + * denominator of a fraction. + */ + public static final class MetricFractionPart { + @SerializedName("jmx") + private String m_jmxInfo = null; + + @SerializedName("ganglia") + private String m_gangliaInfo = null; + + /** + * @return the jmx info, if this metric is jmx-based + */ + public String getJmxInfo() { + return m_jmxInfo; + } + + /** + * @return the ganglia info, if this metric is ganglia-based + */ + public String getGangliaInfo() { + return m_gangliaInfo; + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java new file mode 100644 index 0000000..afb60dd --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.state.alert; + +import com.google.gson.annotations.SerializedName; + +/** + * Alert when the source type is defined as {@link SourceType#PORT} + */ +public class PortSource extends Source { + + @SerializedName("uri") + private String m_uri = null; + + @SerializedName("port") + private int m_port = 0; + + /** + * @return the URI to check for a valid port + */ + public String getUri() { + return m_uri; + } + + /** + * @return the port to check on the given URI. + */ + public int getPort() { + return m_port; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java new file mode 100644 index 0000000..7e63d43 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.state.alert; + +import com.google.gson.annotations.SerializedName; + +/** + * The {@link Reporting} class represents the OK/WARNING/CRITICAL structures in + * an {@link AlertDefinition}. + */ +public class Reporting { + + /** + * + */ + @SerializedName("ok") + private ReportTemplate m_ok; + + /** + * + */ + @SerializedName("warning") + private ReportTemplate m_warning; + + /** + * + */ + @SerializedName("critical") + private ReportTemplate m_critical; + + /** + * @return the WARNING structure or {@code null} if none. + */ + public ReportTemplate getWarning() { + return m_warning; + } + + /** + * @return the CRITICAL structure or {@code null} if none. + */ + public ReportTemplate getCritical() { + return m_critical; + } + + /** + * @return the OK structure or {@code null} if none. + */ + public ReportTemplate getOk() { + return m_ok; + } + + /** + * The {@link ReportTemplate} class is used to pair a label and threshhold + * value. + */ + public static final class ReportTemplate { + @SerializedName("text") + private String m_text; + + @SerializedName("value") + private Double m_value = null; + + /** + * @return the parameterized text of this template or {@code null} if none. + */ + public String getText() { + return m_text; + } + + /** + * @return the threshold value for this template or {@code null} if none. + */ + public Double getValue() { + return m_value; + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java new file mode 100644 index 0000000..13a6057 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.state.alert; + +import com.google.gson.annotations.SerializedName; + +/** + * Alert when the source type is defined as {@link SourceType#SCRIPT} + */ +public class ScriptSource extends Source { + + @SerializedName("path") + private String m_path = null; + + /** + * @return the path to the script file. + */ + public String getPath() { + return m_path; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java index f64b7d2..cdce41c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java @@ -17,6 +17,8 @@ */ package org.apache.ambari.server.state.alert; +import com.google.gson.annotations.SerializedName; + /** * Abstract class that all known alert sources should extend. */ @@ -24,11 +26,20 @@ public abstract class Source { private SourceType type; + @SerializedName("reporting") + private Reporting reporting; + /** * @return the type */ public SourceType getType() { return type; } - + + /** + * @return + */ + public Reporting getReporting() { + return reporting; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/main/java/org/apache/ambari/server/state/alert/SourceType.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/SourceType.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/SourceType.java index 8289d6f..18c13bd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/SourceType.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/SourceType.java @@ -18,7 +18,7 @@ package org.apache.ambari.server.state.alert; /** - * Source type refers to how the alert is to be collected. + * Source type refers to how the alert is to be collected. */ public enum SourceType { /** @@ -36,5 +36,10 @@ public enum SourceType { /** * Source is an aggregate of a collection of other alert states */ - AGGREGATE + AGGREGATE, + + /** + * Source is a ratio of two {@link #METRIC} values. + */ + PERCENT; } http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java index 68cbc92..6b50e16 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java @@ -29,6 +29,7 @@ import java.io.File; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; @@ -54,6 +55,8 @@ import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.Stack; import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.server.state.alert.AlertDefinition; +import org.apache.ambari.server.state.alert.Reporting; +import org.apache.ambari.server.state.alert.Source; import org.apache.ambari.server.state.stack.MetricDefinition; import org.apache.commons.io.FileUtils; import org.junit.Before; @@ -1420,5 +1423,53 @@ public class AmbariMetaInfoTest { Assert.assertNotNull(set); Assert.assertTrue(set.size() > 0); + // find two different definitions and test each one + AlertDefinition nameNodeProcess = null; + AlertDefinition nameNodeCpu = null; + + Iterator<AlertDefinition> iterator = set.iterator(); + while (iterator.hasNext()) { + AlertDefinition definition = iterator.next(); + if (definition.getName().equals("namenode_process")) { + nameNodeProcess = definition; + } + + if (definition.getName().equals("namenode_cpu")) { + nameNodeCpu = definition; + } + } + + assertNotNull(nameNodeProcess); + assertNotNull(nameNodeCpu); + + assertEquals("NameNode host CPU Utilization", nameNodeCpu.getLabel()); + + Source source = nameNodeProcess.getSource(); + assertNotNull(source); + + // test namenode_process + Reporting reporting = source.getReporting(); + assertNotNull(reporting); + assertNotNull(reporting.getOk()); + assertNotNull(reporting.getOk().getText()); + assertNull(reporting.getOk().getValue()); + assertNotNull(reporting.getCritical()); + assertNotNull(reporting.getCritical().getText()); + assertNull(reporting.getCritical().getValue()); + assertNull(reporting.getWarning()); + + // test namenode_cpu + source = nameNodeCpu.getSource(); + reporting = source.getReporting(); + assertNotNull(reporting); + assertNotNull(reporting.getOk()); + assertNotNull(reporting.getOk().getText()); + assertNull(reporting.getOk().getValue()); + assertNotNull(reporting.getCritical()); + assertNotNull(reporting.getCritical().getText()); + assertNotNull(reporting.getCritical().getValue()); + assertNotNull(reporting.getWarning()); + assertNotNull(reporting.getWarning().getText()); + assertNotNull(reporting.getWarning().getValue()); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java index 333f674..7df999e 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java @@ -29,10 +29,12 @@ import static org.easymock.EasyMock.resetToStrict; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; +import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -44,18 +46,24 @@ import org.apache.ambari.server.controller.spi.Request; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.utilities.PredicateBuilder; import org.apache.ambari.server.controller.utilities.PropertyHelper; +import org.apache.ambari.server.metadata.ActionMetadata; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.alert.AlertDefinition; +import org.apache.ambari.server.state.alert.AlertDefinitionFactory; import org.apache.ambari.server.state.alert.AlertDefinitionHash; +import org.apache.ambari.server.state.alert.Source; +import org.apache.ambari.server.state.alert.SourceType; import org.easymock.Capture; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.google.gson.Gson; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Injector; @@ -69,6 +77,7 @@ public class AlertDefinitionResourceProviderTest { private AlertDefinitionDAO dao = null; private AlertDefinitionHash definitionHash = null; + private AlertDefinitionFactory m_factory = new AlertDefinitionFactory(); private Injector m_injector; private static String DEFINITION_UUID = UUID.randomUUID().toString(); @@ -82,6 +91,7 @@ public class AlertDefinitionResourceProviderTest { new InMemoryDefaultTestModule()).with(new MockModule())); AlertDefinitionResourceProvider.init(m_injector); + m_injector.injectMembers(m_factory); } /** @@ -149,6 +159,7 @@ public class AlertDefinitionResourceProviderTest { AlertDefinitionResourceProvider.ALERT_DEF_ID, AlertDefinitionResourceProvider.ALERT_DEF_NAME, AlertDefinitionResourceProvider.ALERT_DEF_LABEL, + AlertDefinitionResourceProvider.ALERT_DEF_SOURCE, AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE); AmbariManagementController amc = createMock(AmbariManagementController.class); @@ -174,9 +185,20 @@ public class AlertDefinitionResourceProviderTest { Resource r = results.iterator().next(); Assert.assertEquals("my_def", r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_NAME)); - Assert.assertEquals("metric", r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE)); + + Assert.assertEquals( + SourceType.METRIC.name(), + r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE)); + + Source source = getMockSource(); + String okJson = source.getReporting().getOk().getText(); + Object reporting = r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_REPORTING); + + Assert.assertTrue(reporting.toString().contains(okJson)); + Assert.assertEquals("Mock Label", r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_LABEL)); + Assert.assertNotNull(r.getPropertyValue("AlertDefinition/source/type")); } @@ -203,14 +225,25 @@ public class AlertDefinitionResourceProviderTest { replay(amc, clusters, cluster, dao, definitionHash); + Gson gson = m_factory.getGson(); + Source source = getMockSource(); + String sourceJson = gson.toJson(source); AlertDefinitionResourceProvider provider = createProvider(amc); Map<String, Object> requestProps = new HashMap<String, Object>(); requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME, "c1"); requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_INTERVAL, "1"); requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_NAME, "my_def"); - requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SERVICE_NAME, "HDFS"); - requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE, "METRIC"); + + requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SERVICE_NAME, + "HDFS"); + + requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE, + sourceJson); + + requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE, + SourceType.METRIC.name()); + requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_LABEL, "Mock Label (Create)"); @@ -230,10 +263,23 @@ public class AlertDefinitionResourceProviderTest { Assert.assertEquals(Integer.valueOf(1), entity.getScheduleInterval()); Assert.assertNull(entity.getScope()); Assert.assertEquals("HDFS", entity.getServiceName()); - Assert.assertNotNull(entity.getSource()); Assert.assertEquals("METRIC", entity.getSourceType()); Assert.assertEquals("Mock Label (Create)", entity.getLabel()); + // verify Source + Assert.assertNotNull(entity.getSource()); + Source actualSource = gson.fromJson(entity.getSource(), Source.class); + Assert.assertNotNull(actualSource); + + assertEquals(source.getReporting().getOk().getText(), + source.getReporting().getOk().getText()); + + assertEquals(source.getReporting().getWarning().getText(), + source.getReporting().getWarning().getText()); + + assertEquals(source.getReporting().getCritical().getText(), + source.getReporting().getCritical().getText()); + verify(amc, clusters, cluster, dao); } @@ -386,7 +432,10 @@ public class AlertDefinitionResourceProviderTest { /** * @return */ - private List<AlertDefinitionEntity> getMockEntities() { + private List<AlertDefinitionEntity> getMockEntities() throws Exception { + Source source = getMockSource(); + String sourceJson = new Gson().toJson(source); + AlertDefinitionEntity entity = new AlertDefinitionEntity(); entity.setClusterId(Long.valueOf(1L)); entity.setComponentName(null); @@ -397,13 +446,36 @@ public class AlertDefinitionResourceProviderTest { entity.setHash(DEFINITION_UUID); entity.setScheduleInterval(Integer.valueOf(2)); entity.setServiceName(null); - entity.setSourceType("metric"); - entity.setSource("{'jmx': 'beanName/attributeName', 'host': '{{aa:123445}}'}"); - + entity.setSourceType(SourceType.METRIC.name()); + entity.setSource(sourceJson); return Arrays.asList(entity); } /** + * @return + */ + private Source getMockSource() throws Exception { + File alertsFile = new File( + "src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json"); + + Assert.assertTrue(alertsFile.exists()); + + Set<AlertDefinition> set = m_factory.getAlertDefinitions(alertsFile, "HDFS"); + AlertDefinition nameNodeCpu = null; + Iterator<AlertDefinition> definitions = set.iterator(); + while (definitions.hasNext()) { + AlertDefinition definition = definitions.next(); + + if (definition.getName().equals("namenode_cpu")) { + nameNodeCpu = definition; + } + } + + Assert.assertNotNull(nameNodeCpu.getSource()); + return nameNodeCpu.getSource(); + } + + /** * */ private class MockModule implements Module { @@ -418,6 +490,7 @@ public class AlertDefinitionResourceProviderTest { EasyMock.createNiceMock(Clusters.class)); binder.bind(Cluster.class).toInstance( EasyMock.createNiceMock(Cluster.class)); + binder.bind(ActionMetadata.class); } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/0ac9cb3f/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json index 85aa3ab..02a9a58 100644 --- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json +++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json @@ -1,18 +1,5 @@ { - "service": [ - ], - "SECONDARY_NAMENODE": [ - { - "name": "secondary_namenode_process", - "label": "Secondary NameNode process", - "interval": 1, - "scope": "service", - "source": { - "type": "PORT", - "config": "{{hdfs-site/dfs.namenode.secondary.http-address}}:50071" - } - } - ], + "service": [], "NAMENODE": [ { "name": "namenode_cpu", @@ -21,7 +8,20 @@ "source": { "type": "METRIC", "jmx": "java.lang:type=OperatingSystem/SystemCpuLoad", - "host": "{{hdfs-site/dfs.namenode.secondary.http-address}}" + "host": "{{hdfs-site/dfs.namenode.secondary.http-address}}", + "reporting": { + "ok": { + "text": "System CPU Load is OK" + }, + "warning": { + "text": "System CPU Load is Nearing Critical", + "value": 70 + }, + "critical": { + "text": "System CPU Load is Critical", + "value": 80 + } + } } }, { @@ -31,8 +31,17 @@ "scope": "host", "source": { "type": "PORT", - "uri": "{{hdfs-site/dfs.namenode.http-address}}:50070" - } + "uri": "{{hdfs-site/dfs.namenode.http-address}}", + "port": 50070, + "reporting": { + "ok": { + "text": "TCP OK - {0:.4f} response on port {1}" + }, + "critical": { + "text": "TCP FAIL - {0:.4f} response on port {1}" + } + } + } }, { "name": "hdfs_last_checkpoint", @@ -46,6 +55,18 @@ } } ], - "DATANODE": [ - ] -} + "SECONDARY_NAMENODE": [ + { + "name": "secondary_namenode_process", + "label": "Secondary NameNode process", + "interval": 1, + "scope": "service", + "source": { + "type": "PORT", + "uri": "{{hdfs-site/dfs.namenode.secondary.http-address}}", + "port": 50070 + } + } + ], + "DATANODE": [] +} \ No newline at end of file