Jian Li
Committed by Gerrit Code Review

Add a set of synchronous method for control plane monitor service

Change-Id: Ib060282dfe9a302a6cf88b9679555f4a2e8127a2
......@@ -73,6 +73,26 @@ public interface ControlPlaneMonitorService {
Optional<DeviceId> deviceId);
/**
* Synchronous version of getLoad.
* Obtains snapshot of control plane load of a specific device.
* The metrics range from control messages and system metrics
* (e.g., CPU and memory info).
* If the device id is not specified, it returns system metrics, otherwise,
* it returns control message stats of the given device.
*
* @param nodeId node identifier
* @param type control metric type
* @param deviceId device identifier
* @return control load snapshot
*/
default ControlLoadSnapshot getLoadSync(NodeId nodeId,
ControlMetricType type,
Optional<DeviceId> deviceId) {
return Tools.futureGetOrElse(getLoad(nodeId, type, deviceId),
TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
}
/**
* Obtains snapshot of control plane load of a specific resource.
* The metrics include I/O device metrics (e.g., disk and network metrics).
*
......@@ -86,6 +106,23 @@ public interface ControlPlaneMonitorService {
String resourceName);
/**
* Synchronous version of getLoad.
* Obtains snapshot of control plane load of a specific resource.
* The metrics include I/O device metrics (e.g., disk and network metrics).
*
* @param nodeId node identifier
* @param type control metric type
* @param resourceName resource name
* @return control load snapshot
*/
default ControlLoadSnapshot getLoadSync(NodeId nodeId,
ControlMetricType type,
String resourceName) {
return Tools.futureGetOrElse(getLoad(nodeId, type, resourceName),
TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
}
/**
* Obtains snapshot of control plane load of a specific device with the
* projected range.
*
......@@ -102,6 +139,26 @@ public interface ControlPlaneMonitorService {
Optional<DeviceId> deviceId);
/**
* Synchronous version of getLoad.
* Obtains snapshot of control plane load of a specific device with the
* projected range.
*
* @param nodeId node identifier
* @param type control metric type
* @param duration projected duration
* @param unit projected time unit
* @param deviceId device identifier
* @return control load snapshot
*/
default ControlLoadSnapshot getLoadSync(NodeId nodeId,
ControlMetricType type,
int duration, TimeUnit unit,
Optional<DeviceId> deviceId) {
return Tools.futureGetOrElse(getLoad(nodeId, type, duration, unit, deviceId),
TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
}
/**
* Obtains snapshot of control plane load of a specific resource with the
* projected range.
*
......@@ -118,6 +175,26 @@ public interface ControlPlaneMonitorService {
String resourceName);
/**
* Synchronous version of getLoad.
* Obtains snapshot of control plane load of a specific resource with the
* projected range.
*
* @param nodeId node identifier
* @param type control metric type
* @param duration projected duration
* @param unit projected time unit
* @param resourceName resource name
* @return control load snapshot
*/
default ControlLoadSnapshot getLoadSync(NodeId nodeId,
ControlMetricType type,
int duration, TimeUnit unit,
String resourceName) {
return Tools.futureGetOrElse(getLoad(nodeId, type, duration, unit, resourceName),
TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
}
/**
* Obtains a list of names of available resources.
*
* @param nodeId node identifier
......
......@@ -17,7 +17,6 @@ package org.onosproject.cpman.cli;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.util.Tools;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cluster.NodeId;
import org.onosproject.cpman.ControlLoadSnapshot;
......@@ -27,8 +26,6 @@ import org.onosproject.net.DeviceId;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import static org.onosproject.cpman.ControlResource.CONTROL_MESSAGE_METRICS;
import static org.onosproject.cpman.ControlResource.CPU_METRICS;
......@@ -47,8 +44,6 @@ public class ControlMetricsStatsListCommand extends AbstractShellCommand {
"averageValue=%d, latestTime=%s";
private static final String INVALID_TYPE = "Invalid control resource type.";
private static final long TIMEOUT_MILLIS = 3000;
@Argument(index = 0, name = "node", description = "ONOS node identifier",
required = true, multiValued = false)
String node = null;
......@@ -91,51 +86,80 @@ public class ControlMetricsStatsListCommand extends AbstractShellCommand {
}
}
/**
* Prints system metric statistic information.
*
* @param service monitor service
* @param nodeId node identifier
* @param typeSet control metric type
*/
private void printMetricsStats(ControlPlaneMonitorService service, NodeId nodeId,
Set<ControlMetricType> typeSet) {
printMetricsStats(service, nodeId, typeSet, null, null);
}
/**
* Prints disk and network metric statistic information.
*
* @param service monitor service
* @param nodeId node identifier
* @param typeSet control metric type
* @param resName resource name
*/
private void printMetricsStats(ControlPlaneMonitorService service, NodeId nodeId,
Set<ControlMetricType> typeSet, String resName) {
printMetricsStats(service, nodeId, typeSet, resName, null);
}
/**
* Prints control message metric statistic information.
*
* @param service monitor service
* @param nodeId node identifier
* @param typeSet control metric type
* @param did device identifier
*/
private void printMetricsStats(ControlPlaneMonitorService service, NodeId nodeId,
Set<ControlMetricType> typeSet, DeviceId did) {
printMetricsStats(service, nodeId, typeSet, null, did);
}
/**
* Prints control plane metric statistic information.
*
* @param service monitor service
* @param nodeId node identifier
* @param typeSet control metric type
* @param resName resource name
* @param did device identifier
*/
private void printMetricsStats(ControlPlaneMonitorService service, NodeId nodeId,
Set<ControlMetricType> typeSet, String resName, DeviceId did) {
if (resName == null && did == null) {
typeSet.forEach(s -> {
CompletableFuture<ControlLoadSnapshot> cf =
service.getLoad(nodeId, s, Optional.empty());
ControlLoadSnapshot cmr =
Tools.futureGetOrElse(cf, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
printRemote(s, cmr);
ControlLoadSnapshot cls = service.getLoadSync(nodeId, s, Optional.empty());
printControlLoadSnapshot(s, cls);
});
} else if (resName == null && did != null) {
} else if (resName == null) {
typeSet.forEach(s -> {
CompletableFuture<ControlLoadSnapshot> cf =
service.getLoad(nodeId, s, Optional.of(did));
ControlLoadSnapshot cmr =
Tools.futureGetOrElse(cf, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
printRemote(s, cmr);
ControlLoadSnapshot cls = service.getLoadSync(nodeId, s, Optional.of(did));
printControlLoadSnapshot(s, cls);
});
} else if (resName != null && did == null) {
} else if (did == null) {
typeSet.forEach(s -> {
CompletableFuture<ControlLoadSnapshot> cf =
service.getLoad(nodeId, s, resName);
ControlLoadSnapshot cmr =
Tools.futureGetOrElse(cf, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
printRemote(s, cmr);
ControlLoadSnapshot cls = service.getLoadSync(nodeId, s, resName);
printControlLoadSnapshot(s, cls);
});
}
}
private void printRemote(ControlMetricType cmType, ControlLoadSnapshot cls) {
/**
* Prints control load snapshot.
*
* @param cmType control metric type
* @param cls control load snapshot
*/
private void printControlLoadSnapshot(ControlMetricType cmType, ControlLoadSnapshot cls) {
if (cls != null) {
print(FMT, cmType.toString(), cls.latest(), cls.average(), cls.time());
} else {
......
......@@ -149,21 +149,15 @@ public class CpmanViewMessageHandler extends UiMessageHandler {
ClusterService cs, DeviceId deviceId) {
Map<ControlMetricType, Long[]> data = Maps.newHashMap();
for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
ControlLoadSnapshot cls;
try {
cls = cpms.getLoad(cs.getLocalNode().id(),
cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES,
Optional.of(deviceId)).get();
// TODO: in some cases, the number of returned dataset is
// less than what we expected (expected -1)
// As a workaround, we simply fill the slot with 0 values,
// such a bug should be fixed with updated RRD4J lib...
data.put(cmt, ArrayUtils.toObject(fillData(cls.recent(), NUM_OF_DATA_POINTS)));
timestamp = cls.time();
} catch (InterruptedException | ExecutionException e) {
log.warn(e.getMessage());
}
ControlLoadSnapshot cls = cpms.getLoadSync(cs.getLocalNode().id(),
cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES, Optional.of(deviceId));
// TODO: in some cases, the number of returned data set is
// less than what we expected (expected -1)
// As a workaround, we simply fill the slot with 0 values,
// such a bug should be fixed with updated RRD4J lib...
data.put(cmt, ArrayUtils.toObject(fillData(cls.recent(), NUM_OF_DATA_POINTS)));
timestamp = cls.time();
}
return data;
}
......
......@@ -18,7 +18,6 @@ package org.onosproject.cpman.rest;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.onlab.util.Tools;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.NodeId;
import org.onosproject.cpman.ControlLoadSnapshot;
......@@ -35,8 +34,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import static org.onosproject.cpman.ControlResource.CONTROL_MESSAGE_METRICS;
import static org.onosproject.cpman.ControlResource.CPU_METRICS;
......@@ -58,7 +55,6 @@ public class ControlMetricsWebResource extends AbstractWebResource {
private final ClusterService clusterService = get(ClusterService.class);
private final NodeId localNodeId = clusterService.getLocalNode().id();
private final ObjectNode root = mapper().createObjectNode();
private static final long TIMEOUT_MILLIS = 1000;
/**
* Returns control message metrics of all devices.
......@@ -251,59 +247,32 @@ public class ControlMetricsWebResource extends AbstractWebResource {
if (name == null && did == null) {
typeSet.forEach(type -> {
ObjectNode metricNode = mapper().createObjectNode();
CompletableFuture<ControlLoadSnapshot> cf =
service.getLoad(nodeId, type, Optional.empty());
if (cf != null) {
ControlLoadSnapshot cmr =
Tools.futureGetOrElse(cf, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
if (cmr != null) {
metricNode.set(toCamelCase(type.toString(), true),
codec(ControlLoadSnapshot.class).encode(cmr, this));
metricsNode.add(metricNode);
}
}
ControlLoadSnapshot cls = service.getLoadSync(nodeId, type, Optional.empty());
processRest(cls, type, metricsNode);
});
} else if (name == null) {
typeSet.forEach(type -> {
ObjectNode metricNode = mapper().createObjectNode();
CompletableFuture<ControlLoadSnapshot> cf =
service.getLoad(nodeId, type, Optional.of(did));
if (cf != null) {
ControlLoadSnapshot cmr =
Tools.futureGetOrElse(cf, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
if (cmr != null) {
metricNode.set(toCamelCase(type.toString(), true),
codec(ControlLoadSnapshot.class).encode(cmr, this));
metricsNode.add(metricNode);
}
}
ControlLoadSnapshot cls = service.getLoadSync(nodeId, type, Optional.of(did));
processRest(cls, type, metricsNode);
});
} else if (did == null) {
typeSet.forEach(type -> {
ObjectNode metricNode = mapper().createObjectNode();
CompletableFuture<ControlLoadSnapshot> cf =
service.getLoad(nodeId, type, name);
if (cf != null) {
ControlLoadSnapshot cmr =
Tools.futureGetOrElse(cf, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS, null);
if (cmr != null) {
metricNode.set(toCamelCase(type.toString(), true),
codec(ControlLoadSnapshot.class).encode(cmr, this));
metricsNode.add(metricNode);
}
}
ControlLoadSnapshot cls = service.getLoadSync(nodeId, type, name);
processRest(cls, type, metricsNode);
});
}
return metricsNode;
}
/**
* Camelizes the input string.
*
* @param value original string
* @param startWithLowerCase flag that determines whether to use lower case
* for the camelized string
* @return camelized string
*/
private String toCamelCase(String value, boolean startWithLowerCase) {
String[] strings = StringUtils.split(value.toLowerCase(), "_");
for (int i = startWithLowerCase ? 1 : 0; i < strings.length; i++) {
......@@ -311,4 +280,21 @@ public class ControlMetricsWebResource extends AbstractWebResource {
}
return StringUtils.join(strings);
}
/**
* Transforms control load snapshot object into JSON object.
*
* @param cls control load snapshot
* @param type control metric type
* @param metricsNode array of JSON node
*/
private void processRest(ControlLoadSnapshot cls, ControlMetricType type, ArrayNode metricsNode) {
ObjectNode metricNode = mapper().createObjectNode();
if (cls != null) {
metricNode.set(toCamelCase(type.toString(), true),
codec(ControlLoadSnapshot.class).encode(cls, this));
metricsNode.add(metricNode);
}
}
}
......
......@@ -183,7 +183,7 @@ public class ControlMetricsResourceTest extends ResourceTest {
public void testResourcePopulatedArray() {
expect(mockControlPlaneMonitorService.availableResourcesSync(anyObject(), anyObject()))
.andReturn(resourceSet).once();
expect(mockControlPlaneMonitorService.getLoad(anyObject(), anyObject(),
expect(mockControlPlaneMonitorService.getLoadSync(anyObject(), anyObject(),
anyString())).andReturn(null).times(4);
replay(mockControlPlaneMonitorService);
......