blob: c0cc6b2ee87cc9fd625e8db0ec5eb4162b44091f [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
*
* Licensed 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.onosproject.drivers.server.gui;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.primitives.Floats;
import org.onosproject.drivers.server.behavior.CpuStatisticsDiscovery;
import org.onosproject.drivers.server.devices.RestServerSBDevice;
import org.onosproject.drivers.server.stats.CpuStatistics;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.chart.ChartModel;
import org.apache.commons.lang.ArrayUtils;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import java.util.Arrays;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.drivers.server.Constants.MSG_UI_DATA_CPU_NULL;
import static org.onosproject.drivers.server.gui.MetricType.CPU;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Message handler for passing CPU load data to the Web UI.
*/
public class CpuViewMessageHandler extends BaseViewMessageHandler {
private static final Logger log = getLogger(CpuViewMessageHandler.class);
private static final String CPU_DATA_REQ = "cpuDataRequest";
private static final String CPU_DATA_RESP = "cpuDataResponse";
private static final String CPUS_LABEL = "cpus";
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(new CpuMessageRequest());
}
private final class CpuMessageRequest
extends BaseViewMessageHandler.ControlMessageRequest {
private CpuMessageRequest() {
super(CPU_DATA_REQ, CPU_DATA_RESP, CPUS_LABEL);
}
@Override
protected String[] getSeries() {
return createIndexedSeries(CPU, MAX_COLUMNS_NB);
}
@Override
protected void populateChart(ChartModel cm, ObjectNode payload) {
DeviceService ds = get(DeviceService.class);
if ((ds == null) || (ds.getAvailableDeviceCount() == 0)) {
fillDataWhenNoDevicePresent(cm, CPU, MAX_COLUMNS_NB);
return;
}
String uri = string(payload, "devId");
// Project only one device over time
if (!Strings.isNullOrEmpty(uri)) {
DeviceId deviceId = DeviceId.deviceId(uri);
RestServerSBDevice serverDev =
(RestServerSBDevice) basicDriver.getController().getDevice(deviceId);
List<CpuStatistics> cpuStats = null;
Map<Integer, Float[]> data = null;
try {
cpuStats = new ArrayList(serverDriver.getCpuStatistics(deviceId));
data = populateCpuDataHistory(deviceId, serverDev.numberOfCpus(), cpuStats);
} catch (Exception ex) {
data = populateZeroMapDataHistory(deviceId, MAX_COLUMNS_NB);
}
checkNotNull(data, MSG_UI_DATA_CPU_NULL);
// Generate a timestamp
LocalDateTime ldt = new LocalDateTime(timestamp);
// Project the data
populateMapMetrics(cm, data, ldt, CPU, NUM_OF_DATA_POINTS);
Set<DeviceId> deviceIds = Sets.newHashSet();
for (Device device : ds.getAvailableDevices()) {
// Only devices that support CPU monitoring are considered
if (device.is(CpuStatisticsDiscovery.class) && serverDev.isActive()) {
deviceIds.add(device.id());
}
}
// Drop down list to select devices
attachDeviceList(cm, deviceIds);
} else {
for (Device device : ds.getAvailableDevices()) {
// Only devices that support CPU monitoring are considered
if (!device.is(CpuStatisticsDiscovery.class)) {
continue;
}
DeviceId deviceId = device.id();
RestServerSBDevice serverDev =
(RestServerSBDevice) basicDriver.getController().getDevice(deviceId);
List<CpuStatistics> cpuStats = null;
Map<Integer, Float> data = null;
try {
cpuStats = new ArrayList(serverDriver.getCpuStatistics(deviceId));
data = populateCpuData(deviceId, serverDev.numberOfCpus(), cpuStats);
} catch (Exception ex) {
data = populateZeroMapData(deviceId, MAX_COLUMNS_NB);
}
checkNotNull(data, MSG_UI_DATA_CPU_NULL);
// Map them to the CPU cores
Map<String, Object> local = Maps.newHashMap();
for (int i = 0; i < data.size(); i++) {
local.put(getIndexedLabel(CPU, i), data.get(i));
}
// Last piece of data is the device ID
if (serverDev.isActive()) {
local.put(LABEL, deviceId);
populateMetric(cm.addDataPoint(deviceId), local);
} else {
local.put(LABEL, "");
populateMetric(cm.addDataPoint(""), local);
}
}
}
}
/**
* Turn the current monitoring data into a data
* structure that can feed the CPU UI memory.
*
* @param deviceId the device ID being monitored
* @param length the length of the array
* @param cpuStats the CPU load per core
* @return a map of CPU metrics to their values
*/
private Map<Integer, Float> populateCpuData(
DeviceId deviceId, int length, List<CpuStatistics> cpuStats) {
Map<Integer, Float> data = initializeMapData(MAX_COLUMNS_NB);
for (CpuStatistics stats : cpuStats) {
int index = stats.id();
// Store it locally
addToCache(deviceId, length, index, stats.load());
// Project the floating point load value in [0, 1] to [0, 100]
Float projectedVal = new Float(stats.load() * (float) 100);
// Now the data is in the right form
data.put(index, projectedVal);
}
return data;
}
/**
* Turn the monitoring data history into a
* data structure that can feed the CPU UI memory.
*
* @param deviceId the device ID being monitored
* @param length the length of the array
* @param cpuStats the CPU load per core
* @return a map of CPU metrics to their arrays of values
*/
private Map<Integer, Float[]> populateCpuDataHistory(
DeviceId deviceId, int length, List<CpuStatistics> cpuStats) {
Map<Integer, Float[]> data = initializeMapDataHistory(MAX_COLUMNS_NB);
for (CpuStatistics stats : cpuStats) {
int index = stats.id();
// Store it locally
addToCache(deviceId, length, index, stats.load());
LruCache<Float> loadCache = getDataHistory(deviceId, index);
if (loadCache == null) {
continue;
}
float[] floatArray = Floats.toArray(Arrays.asList(loadCache.values().toArray(new Float[0])));
// Project the load array to the range of [0, 100]
for (int j = 0; j < floatArray.length; j++) {
floatArray[j] = floatArray[j] * (float) 100;
}
// Fill the missing points
float[] filledLoadArray = fillData(floatArray, NUM_OF_DATA_POINTS);
// Set the data
data.put(index, ArrayUtils.toObject(filledLoadArray));
}
// Keep a timestamp
timestamp = System.currentTimeMillis();
return data;
}
}
}