Collect core objects under one package

Core package will contain all classes important for Dhalion and its
implementations.
This commit is contained in:
Ashvin Agrawal 2018-02-03 15:33:02 -08:00
Родитель 942468e2c2
Коммит 6f08e5ba4f
19 изменённых файлов: 50 добавлений и 446 удалений

Просмотреть файл

@ -5,7 +5,7 @@
<groupId>com.microsoft.dhalion</groupId>
<artifactId>dhalion</artifactId>
<version>0.0.1_2</version>
<version>0.2.1</version>
<packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name>

Просмотреть файл

@ -6,8 +6,8 @@
*/
package com.microsoft.dhalion.api;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Measurement;
import java.util.Collection;

Просмотреть файл

@ -6,8 +6,8 @@
*/
package com.microsoft.dhalion.api;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import java.util.Collection;

Просмотреть файл

@ -7,10 +7,10 @@
package com.microsoft.dhalion.api;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.resolver.Action;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import com.microsoft.dhalion.core.Measurement;
import com.microsoft.dhalion.core.Action;
import com.microsoft.dhalion.state.StateCache;
import java.time.Duration;

Просмотреть файл

@ -6,9 +6,9 @@
*/
package com.microsoft.dhalion.api;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.resolver.Action;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import com.microsoft.dhalion.core.Action;
import java.util.Collection;

Просмотреть файл

@ -6,7 +6,7 @@
*/
package com.microsoft.dhalion.api;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.core.Measurement;
import com.microsoft.dhalion.state.StateCache;
import java.util.Collection;

Просмотреть файл

@ -6,7 +6,7 @@
*/
package com.microsoft.dhalion.api;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.core.Measurement;
import java.time.Duration;
import java.time.Instant;

Просмотреть файл

@ -4,10 +4,9 @@
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.resolver;
package com.microsoft.dhalion.core;
import com.microsoft.dhalion.api.IResolver;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import java.time.Instant;
import java.util.ArrayList;

Просмотреть файл

@ -4,9 +4,7 @@
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.diagnoser;
import com.microsoft.dhalion.detector.Symptom;
package com.microsoft.dhalion.core;
import java.time.Instant;
import java.util.ArrayList;

Просмотреть файл

@ -4,7 +4,7 @@
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.metrics;
package com.microsoft.dhalion.core;
import java.time.Instant;

Просмотреть файл

@ -4,9 +4,7 @@
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.detector;
import com.microsoft.dhalion.metrics.Measurement;
package com.microsoft.dhalion.core;
import java.time.Instant;
import java.util.ArrayList;
@ -25,12 +23,12 @@ public class Symptom {
private final Instant instant;
// measurements corresponding to this symptom
private final Collection<Measurement> metrics;
private final Collection<Measurement> measurements;
public Symptom(String symptomName, Instant instant, Collection<Measurement> metrics) {
public Symptom(String symptomName, Instant instant, Collection<Measurement> measurements) {
this.name = symptomName;
this.instant = instant;
this.metrics = new ArrayList<>(metrics);
this.measurements = new ArrayList<>(measurements);
}
public String getName() {
@ -41,8 +39,8 @@ public class Symptom {
return instant;
}
public Collection<Measurement> getMetrics() {
return Collections.unmodifiableCollection(metrics);
public Collection<Measurement> getMeasurements() {
return Collections.unmodifiableCollection(measurements);
}
@Override
@ -50,7 +48,7 @@ public class Symptom {
return "Symptom{" +
"name='" + name + '\'' +
", instant=" + instant +
", metrics count=" + metrics.size() +
", measurements count=" + measurements.size() +
'}';
}
}

Просмотреть файл

@ -1,121 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.metrics;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
/**
* An {@link ComponentMetrics} holds metrics information for all instances of a component.
*/
public class ComponentMetrics {
// id of the component
protected String name;
// a map of metric name and its value
private HashMap<String, InstanceMetrics> metrics = new HashMap<>();
public ComponentMetrics(String compName) {
this(compName, null);
}
public ComponentMetrics(String compName, String instanceName, String metricName, double value) {
this(compName, null);
if (instanceName != null) {
InstanceMetrics instanceMetrics = new InstanceMetrics(instanceName, metricName, value);
addInstanceMetric(instanceMetrics);
}
}
public ComponentMetrics(String compName, Map<String, InstanceMetrics> instanceMetricsData) {
this.name = compName;
if (instanceMetricsData != null) {
instanceMetricsData.values().stream().forEach(x -> addInstanceMetric(x));
}
}
public void addInstanceMetric(InstanceMetrics instanceMetrics) {
String instanceName = instanceMetrics.getName();
if (metrics.containsKey(instanceName)) {
throw new IllegalArgumentException("Instance metrics exist: " + name);
}
metrics.put(instanceName, instanceMetrics);
}
public HashMap<String, InstanceMetrics> getMetrics() {
return metrics;
}
public InstanceMetrics getMetrics(String instanceName) {
return metrics.get(instanceName);
}
/**
* @param instance name of the instance for which metrics are desired
* @param metric metric name
* @return all known metric values for the requested instance
*/
public Map<Instant, Double> getMetricValues(String instance, String metric) {
InstanceMetrics instanceMetrics = getMetrics(instance);
if (instanceMetrics == null) {
return null;
}
return instanceMetrics.getMetrics().get(metric);
}
/**
* @param instance name of the instance for which metrics are desired
* @param metric metric name
* @return sum of all the values of the requested metric for the instance.
*/
public Double getMetricValueSum(String instance, String metric) {
InstanceMetrics instanceMetrics = getMetrics(instance);
if (instanceMetrics == null) {
return null;
}
return instanceMetrics.getMetricValueSum(metric);
}
public String getName() {
return name;
}
public boolean anyInstanceAboveLimit(String metricName, double limit) {
return metrics.values().stream().anyMatch(x -> x.hasMetricAboveLimit(metricName, limit));
}
/**
* Merges instance metrics in two different objects into one. Input objects are not modified. It
* is assumed that the two input data sets belong to the same component. Hence the data sets
* will contain the same instances.
*
* @return A new {@link ComponentMetrics} instance
*/
public static ComponentMetrics merge(ComponentMetrics data1, ComponentMetrics data2) {
ComponentMetrics mergedData = new ComponentMetrics(data1.getName());
for (InstanceMetrics instance1 : data1.getMetrics().values()) {
InstanceMetrics instance2 = data2.getMetrics(instance1.getName());
if (instance2 != null) {
instance1 = InstanceMetrics.merge(instance1, instance2);
}
mergedData.addInstanceMetric(instance1);
}
return mergedData;
}
@Override
public String toString() {
return "ComponentMetrics{" +
"name='" + name + '\'' +
", metrics=" + metrics +
'}';
}
}

Просмотреть файл

@ -1,110 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.metrics;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
/**
* An {@link InstanceMetrics} holds metrics information for a specific instance.
*/
public class InstanceMetrics {
// id of the instance
protected final String name;
// a map of metric name and its values
private Map<String, Map<Instant, Double>> metrics = new HashMap<>();
public InstanceMetrics(String instanceName) {
this(instanceName, null, 0.0);
}
public InstanceMetrics(String instanceName, String metricName, double value) {
this.name = instanceName;
if (metricName != null) {
addMetric(metricName, value);
}
}
public void addMetric(String name, Map<Instant, Double> values) {
if (metrics.containsKey(name)) {
throw new IllegalArgumentException("Metric exists: " + name);
}
Map<Instant, Double> metricValues = new HashMap<>();
metricValues.putAll(values);
metrics.put(name, metricValues);
}
/**
* Adds a metric and its value for the instance. This is a shorthand method for
* {@link InstanceMetrics#addMetric(String, Map)} method. The assumption is that the metric will
* have only one value.
*
* @param metricName metric name
* @param value metric value
*/
public void addMetric(String metricName, double value) {
Map<Instant, Double> metricValues = new HashMap<>();
metricValues.put(Instant.now(), value);
addMetric(metricName, metricValues);
}
public Map<String, Map<Instant, Double>> getMetrics() {
return metrics;
}
public Double getMetricValueSum(String metricName) {
Map<Instant, Double> values = getMetrics().get(metricName);
if (values == null || values.isEmpty()) {
return null;
}
return values.values().stream().mapToDouble(x -> x.doubleValue()).sum();
}
public String getName() {
return name;
}
public boolean hasMetricAboveLimit(String metricName, double limit) {
Map<Instant, Double> values = metrics.get(metricName);
if (values == null) {
return false;
}
return values.values().stream().anyMatch(x -> x > limit);
}
/**
* Merges instance metrics in two different objects into one. Input objects are not modified. It
* is assumed that the two input data sets belong to the same instance. It is also assumed that
* the two {@link InstanceMetrics} objects to be merged do not contain values for the same
* metric.
*
* @return A new {@link InstanceMetrics} object
*/
public static InstanceMetrics merge(InstanceMetrics data1, InstanceMetrics data2) {
InstanceMetrics mergedData = new InstanceMetrics(data1.getName());
for (String metric : data1.metrics.keySet()) {
mergedData.addMetric(metric, data1.getMetrics().get(metric));
}
for (String metric : data2.metrics.keySet()) {
mergedData.addMetric(metric, data2.getMetrics().get(metric));
}
return mergedData;
}
@Override
public String toString() {
return "InstanceMetrics{" +
"name='" + name +
", metrics=" + metrics +
'}';
}
}

Просмотреть файл

@ -13,10 +13,10 @@ import com.microsoft.dhalion.api.IDiagnoser;
import com.microsoft.dhalion.api.IHealthPolicy;
import com.microsoft.dhalion.api.IResolver;
import com.microsoft.dhalion.api.ISensor;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.resolver.Action;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import com.microsoft.dhalion.core.Measurement;
import com.microsoft.dhalion.core.Action;
import java.time.Duration;
import java.time.Instant;
@ -113,16 +113,16 @@ public class HealthPolicyImpl implements IHealthPolicy {
@Override
public Collection<Measurement> executeSensors() {
Collection<Measurement> metrics = new ArrayList<>();
Collection<Measurement> measurements = new ArrayList<>();
if (sensors == null) {
return metrics;
return measurements;
}
sensors.stream().map(ISensor::fetch)
.filter(Objects::nonNull)
.forEach(metrics::addAll);
.forEach(measurements::addAll);
return metrics;
return measurements;
}
@Override

Просмотреть файл

@ -8,10 +8,10 @@
package com.microsoft.dhalion.policy;
import com.microsoft.dhalion.api.IHealthPolicy;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.resolver.Action;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import com.microsoft.dhalion.core.Measurement;
import com.microsoft.dhalion.core.Action;
import java.time.Duration;
import java.util.Collection;
@ -55,9 +55,9 @@ public class PoliciesExecutor {
}
LOG.info("Executing Policy: " + policy.getClass().getSimpleName());
Collection<Measurement> metrics = policy.executeSensors();
Collection<Measurement> measurements = policy.executeSensors();
// TODO update CacheState
Collection<Symptom> symptoms = policy.executeDetectors(metrics);
Collection<Symptom> symptoms = policy.executeDetectors(measurements);
Collection<Diagnosis> diagnosis = policy.executeDiagnosers(symptoms);
Collection<Action> actions = policy.executeResolvers(diagnosis);
// TODO pretty print

Просмотреть файл

@ -7,10 +7,10 @@
package com.microsoft.dhalion.state;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.resolver.Action;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import com.microsoft.dhalion.core.Measurement;
import com.microsoft.dhalion.core.Action;
import java.time.Duration;
import java.time.Instant;

Просмотреть файл

@ -1,104 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.metrics;
import org.junit.Test;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
public class ComponentMetricsTest {
@Test
public void testComponentMetricsConstruction() {
Map<String, InstanceMetrics> instanceMetricsMap = new HashMap<>();
InstanceMetrics instanceMetrics = new InstanceMetrics("i1");
addTestMetrics(instanceMetrics, "m1", 123);
instanceMetricsMap.put("i1", instanceMetrics);
ComponentMetrics componentMetrics = new ComponentMetrics("c1", instanceMetricsMap);
assertEquals(1, componentMetrics.getMetrics().size());
instanceMetrics = new InstanceMetrics("i2");
addTestMetrics(instanceMetrics, "m1", 321);
componentMetrics.addInstanceMetric(instanceMetrics);
assertEquals(2, componentMetrics.getMetrics().size());
try {
componentMetrics.addInstanceMetric(instanceMetrics);
fail("Should not allow duplicate instance");
} catch (IllegalArgumentException e) {
}
assertEquals(2, componentMetrics.getMetrics().size());
assertEquals(1, componentMetrics.getMetricValues("i1", "m1").size());
assertEquals(123, componentMetrics.getMetricValues("i1", "m1").get(Instant.ofEpochSecond(123)).intValue());
assertEquals(1, componentMetrics.getMetricValues("i2", "m1").size());
assertEquals(321, componentMetrics.getMetricValues("i2", "m1").get(Instant.ofEpochSecond(321)).intValue());
assertNull(componentMetrics.getMetrics("does not exist"));
}
@Test
public void findsInstanceWithMetricAboveLimit() {
Map<String, InstanceMetrics> instanceMetricsMap = new HashMap<>();
InstanceMetrics instanceMetrics = new InstanceMetrics("i1");
addTestMetrics(instanceMetrics, "m1", 123, 345);
instanceMetricsMap.put("i1", instanceMetrics);
instanceMetrics = new InstanceMetrics("i2");
addTestMetrics(instanceMetrics, "m1", 321, 765);
instanceMetricsMap.put("i2", instanceMetrics);
ComponentMetrics componentMetrics = new ComponentMetrics("c1", instanceMetricsMap);
assertTrue(componentMetrics.anyInstanceAboveLimit("m1", 700));
assertFalse(componentMetrics.anyInstanceAboveLimit("m1", 800));
}
@Test
public void testMerge() {
Map<String, InstanceMetrics> instanceMetricsMap = new HashMap<>();
InstanceMetrics instanceMetrics = new InstanceMetrics("i1");
addTestMetrics(instanceMetrics, "m1", 123, 234);
addTestMetrics(instanceMetrics, "m2", 1234, 2345);
instanceMetricsMap.put("i1", instanceMetrics);
instanceMetrics = new InstanceMetrics("i2");
addTestMetrics(instanceMetrics, "m1", 321, 432);
instanceMetricsMap.put("i2", instanceMetrics);
ComponentMetrics componentMetrics1 = new ComponentMetrics("c1", instanceMetricsMap);
assertEquals(1, componentMetrics1.getMetrics("i2").getMetrics().size());
instanceMetricsMap.clear();
instanceMetrics = new InstanceMetrics("i2");
addTestMetrics(instanceMetrics, "m2", 321, 432);
instanceMetricsMap.put("i2", instanceMetrics);
ComponentMetrics componentMetrics2 = new ComponentMetrics("c2", instanceMetricsMap);
ComponentMetrics result = ComponentMetrics.merge(componentMetrics1, componentMetrics2);
assertEquals(2, result.getMetrics().size());
assertEquals(2, result.getMetrics("i1").getMetrics().size());
assertEquals(2, result.getMetrics("i1").getMetrics().size());
}
private void addTestMetrics(InstanceMetrics instance, String metricName, int... values) {
HashMap<Instant, Double> valueMap = new HashMap<>();
for (int value : values) {
valueMap.put(Instant.ofEpochSecond(value), (double) value);
}
instance.addMetric(metricName, valueMap);
}
}

Просмотреть файл

@ -1,56 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This program is made available under the terms of the MIT License.
* See the LICENSE file in the project root for more information.
*/
package com.microsoft.dhalion.metrics;
import org.junit.Test;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class InstanceMetricsTest {
@Test
public void mergesDisjointInstances() {
Map<Instant, Double> m1Values = new HashMap<>();
m1Values.put(Instant.ofEpochSecond(123), 123.0);
m1Values.put(Instant.ofEpochSecond(234), 234.0);
InstanceMetrics instanceMetrics1 = new InstanceMetrics("i1");
instanceMetrics1.addMetric("m1", m1Values);
Map<Instant, Double> m2Values = new HashMap<>();
m2Values.put(Instant.ofEpochSecond(321), 321.0);
m2Values.put(Instant.ofEpochSecond(432), 432.0);
InstanceMetrics instanceMetrics2 = new InstanceMetrics("i1");
instanceMetrics2.addMetric("m2", m2Values);
InstanceMetrics mergedInstanceMetrics
= InstanceMetrics.merge(instanceMetrics1, instanceMetrics2);
assertEquals(2, mergedInstanceMetrics.getMetrics().size());
assertNotNull(mergedInstanceMetrics.getMetrics().get("m1"));
assertNotNull(mergedInstanceMetrics.getMetrics().get("m2"));
assertEquals(2, mergedInstanceMetrics.getMetrics().get("m1").size());
assertEquals(2, mergedInstanceMetrics.getMetrics().get("m2").size());
assertEquals(123, mergedInstanceMetrics.getMetrics().get("m1").get(Instant.ofEpochSecond(123)).intValue());
assertEquals(432, mergedInstanceMetrics.getMetrics().get("m2").get(Instant.ofEpochSecond(432)).intValue());
}
@Test(expected = IllegalArgumentException.class)
public void failsOnDuplicateMetricMerge() {
InstanceMetrics instanceMetrics1 = new InstanceMetrics("i1");
instanceMetrics1.addMetric("m1", new HashMap<>());
InstanceMetrics instanceMetrics2 = new InstanceMetrics("i1");
instanceMetrics2.addMetric("m1", new HashMap<>());
InstanceMetrics.merge(instanceMetrics1, instanceMetrics2);
}
}

Просмотреть файл

@ -8,10 +8,10 @@
package com.microsoft.dhalion.policy;
import com.microsoft.dhalion.api.IHealthPolicy;
import com.microsoft.dhalion.detector.Symptom;
import com.microsoft.dhalion.diagnoser.Diagnosis;
import com.microsoft.dhalion.metrics.Measurement;
import com.microsoft.dhalion.resolver.Action;
import com.microsoft.dhalion.core.Symptom;
import com.microsoft.dhalion.core.Diagnosis;
import com.microsoft.dhalion.core.Measurement;
import com.microsoft.dhalion.core.Action;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
@ -48,15 +48,15 @@ public class PoliciesExecutorTest {
@Test
public void verifyPolicyExecutionOrder() throws Exception {
List<Measurement> metrics = new ArrayList<>();
List<Measurement> measurements = new ArrayList<>();
List<Symptom> symptoms = new ArrayList<>();
List<Diagnosis> diagnosis = new ArrayList<>();
List<Action> actions = new ArrayList<>();
IHealthPolicy mockPolicy = mock(IHealthPolicy.class);
when(mockPolicy.getDelay()).thenReturn(Duration.ZERO);
when(mockPolicy.executeSensors()).thenReturn(metrics);
when(mockPolicy.executeDetectors(metrics)).thenReturn(symptoms);
when(mockPolicy.executeSensors()).thenReturn(measurements);
when(mockPolicy.executeDetectors(measurements)).thenReturn(symptoms);
when(mockPolicy.executeDiagnosers(symptoms)).thenReturn(diagnosis);
when(mockPolicy.executeResolvers(diagnosis)).thenReturn(actions);
@ -67,7 +67,7 @@ public class PoliciesExecutorTest {
verify(mockPolicy, timeout(50l).atLeastOnce()).executeResolvers(diagnosis);
InOrder order = Mockito.inOrder(mockPolicy);
order.verify(mockPolicy).executeSensors();
order.verify(mockPolicy).executeDetectors(metrics);
order.verify(mockPolicy).executeDetectors(measurements);
order.verify(mockPolicy).executeDiagnosers(symptoms);
order.verify(mockPolicy).executeResolvers(diagnosis);