| /* |
| * Copyright 2017-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; |
| |
| import org.onosproject.drivers.server.behavior.CpuStatisticsDiscovery; |
| import org.onosproject.drivers.server.behavior.MonitoringStatisticsDiscovery; |
| import org.onosproject.drivers.server.devices.CpuDevice; |
| import org.onosproject.drivers.server.devices.CpuVendor; |
| import org.onosproject.drivers.server.devices.NicDevice; |
| import org.onosproject.drivers.server.devices.NicRxFilter; |
| import org.onosproject.drivers.server.devices.NicRxFilter.RxFilter; |
| import org.onosproject.drivers.server.devices.ServerDeviceDescription; |
| import org.onosproject.drivers.server.devices.RestServerSBDevice; |
| import org.onosproject.drivers.server.stats.CpuStatistics; |
| import org.onosproject.drivers.server.stats.MonitoringStatistics; |
| import org.onosproject.drivers.server.stats.TimingStatistics; |
| |
| import org.onosproject.drivers.server.impl.devices.DefaultCpuDevice; |
| import org.onosproject.drivers.server.impl.devices.DefaultNicDevice; |
| import org.onosproject.drivers.server.impl.devices.DefaultRestServerSBDevice; |
| import org.onosproject.drivers.server.impl.devices.DefaultServerDeviceDescription; |
| import org.onosproject.drivers.server.impl.stats.DefaultCpuStatistics; |
| import org.onosproject.drivers.server.impl.stats.DefaultMonitoringStatistics; |
| import org.onosproject.drivers.server.impl.stats.DefaultTimingStatistics; |
| |
| import org.onlab.packet.ChassisId; |
| import org.onosproject.net.AnnotationKeys; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.DefaultAnnotations; |
| import org.onosproject.net.behaviour.DevicesDiscovery; |
| import org.onosproject.net.device.DeviceDescription; |
| import org.onosproject.net.device.DeviceDescriptionDiscovery; |
| import org.onosproject.net.device.DefaultPortStatistics; |
| import org.onosproject.net.device.DefaultPortDescription; |
| import org.onosproject.net.device.PortDescription; |
| import org.onosproject.net.device.PortStatistics; |
| import org.onosproject.net.device.PortStatisticsDiscovery; |
| import org.onosproject.net.Port; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.protocol.rest.RestSBDevice; |
| import org.onosproject.protocol.rest.RestSBDevice.AuthenticationScheme; |
| |
| import org.slf4j.Logger; |
| |
| import com.fasterxml.jackson.core.type.TypeReference; |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.databind.node.ObjectNode; |
| |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.ImmutableList; |
| |
| import javax.ws.rs.ProcessingException; |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Discovers the device details of |
| * REST-based commodity server devices. |
| */ |
| public class ServerDevicesDiscovery extends BasicServerDriver |
| implements DevicesDiscovery, DeviceDescriptionDiscovery, |
| PortStatisticsDiscovery, CpuStatisticsDiscovery, |
| MonitoringStatisticsDiscovery { |
| |
| private final Logger log = getLogger(getClass()); |
| |
| /** |
| * Resource endpoints of the server agent (REST server-side). |
| */ |
| private static final String RESOURCE_DISCOVERY_URL = BASE_URL + "/resources"; |
| private static final String GLOBAL_STATS_URL = BASE_URL + "/stats"; |
| private static final String SERVICE_CHAINS_STATS_URL = BASE_URL + "/chains_stats"; // + /ID |
| |
| /** |
| * Parameters to be exchanged with the server's agent. |
| */ |
| private static final String PARAM_ID = "id"; |
| private static final String PARAM_CPUS = "cpus"; |
| private static final String PARAM_MANUFACTURER = "manufacturer"; |
| private static final String PARAM_HW_VENDOR = "hwVersion"; |
| private static final String PARAM_SW_VENDOR = "swVersion"; |
| private static final String PARAM_SERIAL = "serial"; |
| private static final String PARAM_NICS = "nics"; |
| private static final String PARAM_TIMING_STATS = "timing_stats"; |
| private static final String PARAM_TIMING_AUTOSCALE = "autoscale_timing_stats"; |
| |
| private static final String NIC_PARAM_ID = "id"; |
| private static final String NIC_PARAM_PORT_TYPE = "portType"; |
| private static final String NIC_PARAM_PORT_TYPE_FIBER = "fiber"; |
| private static final String NIC_PARAM_PORT_TYPE_COPPER = "copper"; |
| private static final String NIC_PARAM_SPEED = "speed"; |
| private static final String NIC_PARAM_STATUS = "status"; |
| private static final String NIC_PARAM_HW_ADDR = "hwAddr"; |
| private static final String NIC_PARAM_RX_FILTER = "rxFilter"; |
| private static final String NIC_PARAM_RX_METHOD = "method"; |
| private static final String NIC_PARAM_RX_METHOD_VALUES = "values"; |
| |
| /** |
| * NIC statistics. |
| */ |
| private static final String NIC_STATS_TX_COUNT = "txCount"; |
| private static final String NIC_STATS_TX_BYTES = "txBytes"; |
| private static final String NIC_STATS_TX_DROPS = "txDropped"; |
| private static final String NIC_STATS_TX_ERRORS = "txErrors"; |
| private static final String NIC_STATS_RX_COUNT = "rxCount"; |
| private static final String NIC_STATS_RX_BYTES = "rxBytes"; |
| private static final String NIC_STATS_RX_DROPS = "rxDropped"; |
| private static final String NIC_STATS_RX_ERRORS = "rxErrors"; |
| |
| /** |
| * CPU statistics. |
| */ |
| private static final String CPU_PARAM_ID = "id"; |
| private static final String CPU_PARAM_VENDOR = "vendor"; |
| private static final String CPU_PARAM_FREQUENCY = "frequency"; |
| private static final String CPU_PARAM_LOAD = "load"; |
| private static final String CPU_PARAM_STATUS = "busy"; |
| private static final String CPU_STATS_BUSY_CPUS = "busyCpus"; |
| private static final String CPU_STATS_FREE_CPUS = "freeCpus"; |
| |
| /** |
| * Timing statistics. |
| */ |
| private static final String TIMING_PARAM_PARSE = "parse"; |
| private static final String TIMING_PARAM_LAUNCH = "launch"; |
| private static final String TIMING_PARAM_AUTOSCALE = "autoscale"; |
| |
| /** |
| * Auxiliary constants. |
| */ |
| private static final short DISCOVERY_RETRIES = 3; |
| private static final String CPU_VENDOR_NULL = "Unsupported CPU vendor" + |
| " Choose one in: " + BasicServerDriver.enumTypesToString(CpuVendor.class); |
| private static final String NIC_RX_FILTER_NULL = "Unsupported NIC Rx filter" + |
| " Choose one in: " + BasicServerDriver.enumTypesToString(RxFilter.class); |
| |
| /** |
| * Port types that usually appear in commodity servers. |
| */ |
| public static final Map<String, Port.Type> PORT_TYPE_MAP = |
| Collections.unmodifiableMap( |
| new HashMap<String, Port.Type>() { |
| { |
| put(NIC_PARAM_PORT_TYPE_FIBER, Port.Type.FIBER); |
| put(NIC_PARAM_PORT_TYPE_COPPER, Port.Type.COPPER); |
| } |
| } |
| ); |
| |
| /** |
| * Constructs server device discovery. |
| */ |
| public ServerDevicesDiscovery() { |
| super(); |
| log.debug("Started"); |
| } |
| |
| @Override |
| public Set<DeviceId> deviceIds() { |
| // Set of devices to return |
| Set<DeviceId> devices = new HashSet<DeviceId>(); |
| |
| DeviceId deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| devices.add(deviceId); |
| |
| return devices; |
| } |
| |
| @Override |
| public DeviceDescription deviceDetails(DeviceId deviceId) { |
| return getDeviceDetails(deviceId); |
| } |
| |
| @Override |
| public DeviceDescription discoverDeviceDetails() { |
| return getDeviceDetails(null); |
| } |
| |
| /** |
| * Query a server to retrieve its features. |
| * |
| * @param deviceId the device ID to be queried |
| * @return a DeviceDescription with the device's features |
| */ |
| private DeviceDescription getDeviceDetails(DeviceId deviceId) { |
| // Create a description for this server device |
| ServerDeviceDescription desc = null; |
| |
| // Retrieve the device ID, if null given |
| if (deviceId == null) { |
| deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| } |
| |
| // Get the device |
| RestSBDevice device = getController().getDevice(deviceId); |
| checkNotNull(device, DEVICE_NULL); |
| |
| // Hit the path that provides the server's resources |
| InputStream response = null; |
| try { |
| response = getController().get( |
| deviceId, |
| RESOURCE_DISCOVERY_URL, |
| JSON |
| ); |
| } catch (ProcessingException pEx) { |
| log.error("Failed to discover the device details of: {}", deviceId); |
| return desc; |
| } |
| |
| // Load the JSON into objects |
| ObjectMapper mapper = new ObjectMapper(); |
| Map<String, Object> jsonMap = null; |
| JsonNode jsonNode = null; |
| ObjectNode objNode = null; |
| try { |
| jsonMap = mapper.readValue(response, Map.class); |
| jsonNode = mapper.convertValue(jsonMap, JsonNode.class); |
| objNode = (ObjectNode) jsonNode; |
| } catch (IOException ioEx) { |
| log.error("Failed to discover the device details of: {}", deviceId); |
| return desc; |
| } |
| |
| if (jsonMap == null) { |
| log.error("Failed to discover the device details of: {}", deviceId); |
| return desc; |
| } |
| |
| // Get all the attributes |
| String id = get(jsonNode, PARAM_ID); |
| String vendor = get(jsonNode, PARAM_MANUFACTURER); |
| String hw = get(jsonNode, PARAM_HW_VENDOR); |
| String sw = get(jsonNode, PARAM_SW_VENDOR); |
| String serial = get(jsonNode, PARAM_SERIAL); |
| |
| // CPUs are composite attributes |
| Set<CpuDevice> cpuSet = new HashSet<CpuDevice>(); |
| JsonNode cpuNode = objNode.path(PARAM_CPUS); |
| |
| // Construct CPU objects |
| for (JsonNode cn : cpuNode) { |
| ObjectNode cpuObjNode = (ObjectNode) cn; |
| |
| // All the CPU attributes |
| int cpuId = cpuObjNode.path(CPU_PARAM_ID).asInt(); |
| String cpuVendorStr = get(cn, CPU_PARAM_VENDOR); |
| long cpuFrequency = cpuObjNode.path(CPU_PARAM_FREQUENCY).asLong(); |
| |
| // Verify that this is a valid vendor |
| CpuVendor cpuVendor = CpuVendor.getByName(cpuVendorStr); |
| checkNotNull(cpuVendor, CPU_VENDOR_NULL); |
| |
| // Construct a CPU device |
| CpuDevice cpu = new DefaultCpuDevice(cpuId, cpuVendor, cpuFrequency); |
| |
| // Add it to the set |
| cpuSet.add(cpu); |
| } |
| |
| // NICs are composite attributes too |
| Set<NicDevice> nicSet = new HashSet<NicDevice>(); |
| JsonNode nicNode = objNode.path(PARAM_NICS); |
| |
| // Construct NIC objects |
| for (JsonNode nn : nicNode) { |
| ObjectNode nicObjNode = (ObjectNode) nn; |
| |
| // All the NIC attributes |
| String nicId = get(nn, NIC_PARAM_ID); |
| int port = Integer.parseInt(nicId.replaceAll("\\D+", "")); |
| long speed = nicObjNode.path(NIC_PARAM_SPEED).asLong(); |
| String portTypeStr = get(nn, NIC_PARAM_PORT_TYPE); |
| Port.Type portType = PORT_TYPE_MAP.get(portTypeStr); |
| if (portType == null) { |
| throw new IllegalArgumentException( |
| portTypeStr + " is not a valid port type for NIC " + nicId |
| ); |
| } |
| boolean status = nicObjNode.path(NIC_PARAM_STATUS).asInt() > 0; |
| String hwAddr = get(nn, NIC_PARAM_HW_ADDR); |
| JsonNode tagNode = nicObjNode.path(NIC_PARAM_RX_FILTER); |
| if (tagNode == null) { |
| throw new IllegalArgumentException( |
| "The Rx filters of NIC " + nicId + " are not reported" |
| ); |
| } |
| |
| // Convert the JSON list into an array of strings |
| List<String> rxFilters = null; |
| try { |
| rxFilters = mapper.readValue( |
| tagNode.traverse(), |
| new TypeReference<ArrayList<String>>() { } |
| ); |
| } catch (IOException ioEx) { |
| continue; |
| } |
| |
| // Parse the array of strings and create an RxFilter object |
| NicRxFilter rxFilterMechanism = new NicRxFilter(); |
| for (String s : rxFilters) { |
| // Verify that this is a valid Rx filter |
| RxFilter rf = RxFilter.getByName(s); |
| checkNotNull(rf, NIC_RX_FILTER_NULL); |
| |
| rxFilterMechanism.addRxFilter(rf); |
| } |
| |
| // Construct a NIC device for this server |
| NicDevice nic = new DefaultNicDevice( |
| nicId, port, portType, speed, status, hwAddr, rxFilterMechanism |
| ); |
| |
| // Add it to the set |
| nicSet.add(nic); |
| } |
| |
| /** |
| * Construct a complete server device object. |
| * Lists of NICs and CPUs extend the information |
| * already in RestSBDevice (parent class). |
| */ |
| RestServerSBDevice dev = new DefaultRestServerSBDevice( |
| device.ip(), device.port(), device.username(), |
| device.password(), device.protocol(), device.url(), |
| device.isActive(), device.testUrl().toString(), |
| vendor, hw, sw, AuthenticationScheme.BASIC, "", |
| cpuSet, nicSet |
| ); |
| checkNotNull(dev, DEVICE_NULL); |
| |
| // Updates the controller with the complete device information |
| getController().removeDevice(deviceId); |
| getController().addDevice((RestSBDevice) dev); |
| |
| /** |
| * TODO: Create a new Device type |
| * Device.Type.COMMODITY_SERVER |
| * and add a new icon in the GUI. |
| */ |
| try { |
| desc = new DefaultServerDeviceDescription( |
| new URI(id), Device.Type.OTHER, vendor, |
| hw, sw, serial, new ChassisId(), |
| cpuSet, nicSet, DefaultAnnotations.EMPTY |
| ); |
| } catch (URISyntaxException uEx) { |
| log.error( |
| "Failed to create a server device description for: {}", deviceId |
| ); |
| return null; |
| } |
| |
| log.info("Device's {} details sent to the controller", deviceId); |
| |
| return desc; |
| } |
| |
| @Override |
| public List<PortDescription> discoverPortDetails() { |
| // List of port descriptions to return |
| List<PortDescription> portDescriptions = Lists.newArrayList(); |
| |
| // Retrieve the device ID |
| DeviceId deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| // .. and object |
| RestServerSBDevice device = null; |
| |
| /* |
| * In case this method is called before discoverDeviceDetails, |
| * there is missing information to be gathered. |
| */ |
| short i = 0; |
| while ((device == null) && (i < DISCOVERY_RETRIES)) { |
| i++; |
| |
| try { |
| device = (RestServerSBDevice) getController().getDevice(deviceId); |
| } catch (ClassCastException ccEx) { |
| try { |
| Thread.sleep(1); |
| } catch (InterruptedException intEx) { |
| // Just retry |
| continue; |
| } |
| } |
| |
| // No device |
| if (device == null) { |
| // This method will add the device to the RestSBController |
| this.getDeviceDetails(deviceId); |
| } |
| } |
| |
| if ((device == null) || (device.nics() == null)) { |
| log.error("No ports available on {}", deviceId); |
| return ImmutableList.copyOf(portDescriptions); |
| } |
| |
| // Sorted list of NIC ports |
| Set<NicDevice> nics = new TreeSet(device.nics()); |
| |
| // Iterate through the NICs of this device to populate the list |
| long portCounter = 0; |
| for (NicDevice nic : nics) { |
| // The port number of this NIC |
| PortNumber portNumber = PortNumber.portNumber(++portCounter); |
| |
| // Include the name of this device as an annotation |
| DefaultAnnotations.Builder annotations = DefaultAnnotations.builder() |
| .set(AnnotationKeys.PORT_NAME, nic.id()); |
| |
| // Create a port description and add it to the list |
| portDescriptions.add( |
| new DefaultPortDescription( |
| portNumber, nic.status(), |
| nic.portType(), nic.speed(), |
| annotations.build() |
| ) |
| ); |
| |
| log.info( |
| "Port discovery on device {}: NIC {} is {} at {} Mbps", |
| deviceId, nic.port(), nic.status() ? "up" : "down", |
| nic.speed() |
| ); |
| } |
| |
| return ImmutableList.copyOf(portDescriptions); |
| } |
| |
| @Override |
| public Collection<PortStatistics> discoverPortStatistics() { |
| // Retrieve the device ID |
| DeviceId deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| |
| // Get port statistics for this device |
| return getPortStatistics(deviceId); |
| } |
| |
| /** |
| * Query a server to retrieve its port statistics. |
| * |
| * @param deviceId the device ID to be queried |
| * @return list of (per port) PortStatistics |
| */ |
| private Collection<PortStatistics> getPortStatistics(DeviceId deviceId) { |
| // List of port statistics to return |
| Collection<PortStatistics> portStats = null; |
| |
| // Get global monitoring statistics |
| MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId); |
| if (monStats == null) { |
| return portStats; |
| } |
| |
| // Filter out the NIC statistics |
| portStats = monStats.nicStatisticsAll(); |
| if (portStats == null) { |
| return portStats; |
| } |
| |
| log.debug("Port statistics: {}", portStats.toString()); |
| |
| return portStats; |
| } |
| |
| @Override |
| public Collection<CpuStatistics> discoverCpuStatistics() { |
| // Retrieve the device ID |
| DeviceId deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| |
| // Get CPU statistics for this device |
| return getCpuStatistics(deviceId); |
| } |
| |
| /** |
| * Query a server to retrieve its CPU statistics. |
| * |
| * @param deviceId the device ID to be queried |
| * @return list of (per core) CpuStatistics |
| */ |
| private Collection<CpuStatistics> getCpuStatistics(DeviceId deviceId) { |
| // List of port statistics to return |
| Collection<CpuStatistics> cpuStats = null; |
| |
| // Get global monitoring statistics |
| MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId); |
| if (monStats == null) { |
| return cpuStats; |
| } |
| |
| // Filter out the CPU statistics |
| cpuStats = monStats.cpuStatisticsAll(); |
| if (cpuStats == null) { |
| return cpuStats; |
| } |
| |
| log.debug("CPU statistics: {}", cpuStats.toString()); |
| |
| return cpuStats; |
| } |
| |
| @Override |
| public MonitoringStatistics discoverGlobalMonitoringStatistics() { |
| // Retrieve the device ID |
| DeviceId deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| |
| // Get global monitoring statistics for this device |
| return getGlobalMonitoringStatistics(deviceId); |
| } |
| |
| /** |
| * Query a server to retrieve its global monitoring statistics. |
| * |
| * @param deviceId the device ID to be queried |
| * @return global monitoring statistics |
| */ |
| private MonitoringStatistics getGlobalMonitoringStatistics(DeviceId deviceId) { |
| // Monitoring statistics to return |
| MonitoringStatistics monStats = null; |
| |
| RestServerSBDevice device = null; |
| try { |
| device = (RestServerSBDevice) getController().getDevice(deviceId); |
| } catch (ClassCastException ccEx) { |
| log.error( |
| "Failed to retrieve global monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| checkNotNull(device, DEVICE_NULL); |
| |
| // Hit the path that provides the server's global resources |
| InputStream response = null; |
| try { |
| response = getController().get( |
| deviceId, |
| GLOBAL_STATS_URL, |
| JSON |
| ); |
| } catch (ProcessingException pEx) { |
| log.error( |
| "Failed to retrieve global monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| |
| // Load the JSON into objects |
| ObjectMapper mapper = new ObjectMapper(); |
| Map<String, Object> jsonMap = null; |
| JsonNode jsonNode = null; |
| ObjectNode objNode = null; |
| try { |
| jsonMap = mapper.readValue(response, Map.class); |
| jsonNode = mapper.convertValue(jsonMap, JsonNode.class); |
| objNode = (ObjectNode) jsonNode; |
| } catch (IOException ioEx) { |
| log.error( |
| "Failed to retrieve global monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| |
| if (jsonMap == null) { |
| log.error( |
| "Failed to retrieve global monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| |
| // Get high-level CPU statistics |
| int busyCpus = objNode.path(CPU_STATS_BUSY_CPUS).asInt(); |
| int freeCpus = objNode.path(CPU_STATS_FREE_CPUS).asInt(); |
| |
| // Get a list of CPU statistics per core |
| Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode); |
| |
| // Get a list of port statistics |
| Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode); |
| |
| // Get zero timing statistics |
| TimingStatistics timinsgStats = getZeroTimingStatistics(); |
| |
| // Ready to construct the grand object |
| DefaultMonitoringStatistics.Builder statsBuilder = |
| DefaultMonitoringStatistics.builder(); |
| |
| statsBuilder.setDeviceId(deviceId) |
| .setTimingStatistics(timinsgStats) |
| .setCpuStatistics(cpuStats) |
| .setNicStatistics(nicStats) |
| .build(); |
| |
| monStats = statsBuilder.build(); |
| |
| log.debug("Global monitoring statistics: {}", monStats.toString()); |
| |
| return monStats; |
| } |
| |
| @Override |
| public MonitoringStatistics discoverMonitoringStatistics(URI tcId) { |
| // Retrieve the device ID |
| DeviceId deviceId = getHandler().data().deviceId(); |
| checkNotNull(deviceId, DEVICE_ID_NULL); |
| |
| // Get resource-specific monitoring statistics for this device |
| return getMonitoringStatistics(deviceId, tcId); |
| } |
| |
| /** |
| * Query a server to retrieve monitoring statistics for a |
| * specific resource (i.e., traffic class). |
| * |
| * @param deviceId the device ID to be queried |
| * @param tcId the ID of the traffic class to be monitored |
| * @return resource-specific monitoring statistics |
| */ |
| private MonitoringStatistics getMonitoringStatistics(DeviceId deviceId, URI tcId) { |
| // Monitoring statistics to return |
| MonitoringStatistics monStats = null; |
| |
| RestServerSBDevice device = null; |
| try { |
| device = (RestServerSBDevice) getController().getDevice(deviceId); |
| } catch (ClassCastException ccEx) { |
| log.error( |
| "Failed to retrieve monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| checkNotNull(device, DEVICE_NULL); |
| |
| // Create a resource-specific URL |
| String scUrl = SERVICE_CHAINS_STATS_URL + "/" + tcId.toString(); |
| |
| // Hit the path that provides the server's specific resources |
| InputStream response = null; |
| try { |
| response = getController().get( |
| deviceId, |
| scUrl, |
| JSON |
| ); |
| } catch (ProcessingException pEx) { |
| log.error( |
| "Failed to retrieve monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| |
| // Load the JSON into objects |
| ObjectMapper mapper = new ObjectMapper(); |
| Map<String, Object> jsonMap = null; |
| JsonNode jsonNode = null; |
| ObjectNode objNode = null; |
| try { |
| jsonMap = mapper.readValue(response, Map.class); |
| jsonNode = mapper.convertValue(jsonMap, JsonNode.class); |
| objNode = (ObjectNode) jsonNode; |
| } catch (IOException ioEx) { |
| log.error( |
| "Failed to retrieve monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| |
| if (jsonMap == null) { |
| log.error( |
| "Failed to retrieve monitoring statistics from device {}", |
| deviceId |
| ); |
| return monStats; |
| } |
| |
| // Get the ID of the traffic class |
| String id = get(jsonNode, PARAM_ID); |
| |
| // And verify that this is the traffic class we want to monitor |
| if (!id.equals(tcId.toString())) { |
| throw new IllegalStateException( |
| "Failed to retrieve monitoring data for traffic class " + tcId + |
| ". Traffic class ID does not agree." |
| ); |
| } |
| |
| // Get a list of CPU statistics per core |
| Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode); |
| |
| // Get a list of port statistics |
| Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode); |
| |
| // Get timing statistics |
| TimingStatistics timinsgStats = parseTimingStatistics(objNode); |
| |
| // Ready to construct the grand object |
| DefaultMonitoringStatistics.Builder statsBuilder = |
| DefaultMonitoringStatistics.builder(); |
| |
| statsBuilder.setDeviceId(deviceId) |
| .setTimingStatistics(timinsgStats) |
| .setCpuStatistics(cpuStats) |
| .setNicStatistics(nicStats) |
| .build(); |
| |
| monStats = statsBuilder.build(); |
| |
| log.debug("Monitoring statistics: {}", monStats.toString()); |
| |
| return monStats; |
| } |
| |
| /** |
| * Parse the input JSON object, looking for CPU-related |
| * statistics. Upon success, construct and return a list |
| * of CPU statistics objects. |
| * |
| * @param deviceId the device ID that sent the JSON object |
| * @param objNode input JSON node with CPU statistics information |
| * @return list of (per core) CpuStatistics |
| */ |
| private Collection<CpuStatistics> parseCpuStatistics( |
| DeviceId deviceId, JsonNode objNode) { |
| Collection<CpuStatistics> cpuStats = Lists.newArrayList(); |
| |
| if (objNode == null) { |
| return cpuStats; |
| } |
| |
| JsonNode cpuNode = objNode.path(PARAM_CPUS); |
| |
| for (JsonNode cn : cpuNode) { |
| ObjectNode cpuObjNode = (ObjectNode) cn; |
| |
| // CPU ID with its load and status |
| int cpuId = cpuObjNode.path(CPU_PARAM_ID).asInt(); |
| float cpuLoad = cpuObjNode.path(CPU_PARAM_LOAD).floatValue(); |
| boolean isBusy = cpuObjNode.path(CPU_PARAM_STATUS).booleanValue(); |
| |
| // Incorporate these statistics into an object |
| DefaultCpuStatistics.Builder cpuBuilder = |
| DefaultCpuStatistics.builder(); |
| |
| cpuBuilder.setDeviceId(deviceId) |
| .setId(cpuId) |
| .setLoad(cpuLoad) |
| .setIsBusy(isBusy) |
| .build(); |
| |
| // We have statistics for this CPU core |
| cpuStats.add(cpuBuilder.build()); |
| } |
| |
| return cpuStats; |
| } |
| |
| /** |
| * Parse the input JSON object, looking for NIC-related |
| * statistics. Upon success, construct and return a list |
| * of NIC statistics objects. |
| * |
| * @param deviceId the device ID that sent the JSON object |
| * @param objNode input JSON node with NIC statistics information |
| * @return list of (per port) PortStatistics |
| */ |
| private Collection<PortStatistics> parseNicStatistics( |
| DeviceId deviceId, JsonNode objNode) { |
| Collection<PortStatistics> nicStats = Lists.newArrayList(); |
| |
| if (objNode == null) { |
| return nicStats; |
| } |
| |
| JsonNode nicNode = objNode.path(PARAM_NICS); |
| |
| for (JsonNode nn : nicNode) { |
| ObjectNode nicObjNode = (ObjectNode) nn; |
| |
| // All the NIC attributes |
| String nicId = get(nn, NIC_PARAM_ID); |
| int port = Integer.parseInt(nicId.replaceAll("\\D+", "")); |
| |
| long rxCount = nicObjNode.path(NIC_STATS_RX_COUNT).asLong(); |
| long rxBytes = nicObjNode.path(NIC_STATS_RX_BYTES).asLong(); |
| long rxDropped = nicObjNode.path(NIC_STATS_RX_DROPS).asLong(); |
| long rxErrors = nicObjNode.path(NIC_STATS_RX_ERRORS).asLong(); |
| long txCount = nicObjNode.path(NIC_STATS_TX_COUNT).asLong(); |
| long txBytes = nicObjNode.path(NIC_STATS_TX_BYTES).asLong(); |
| long txDropped = nicObjNode.path(NIC_STATS_TX_DROPS).asLong(); |
| long txErrors = nicObjNode.path(NIC_STATS_TX_ERRORS).asLong(); |
| |
| // Incorporate these statistics into an object |
| DefaultPortStatistics.Builder nicBuilder = |
| DefaultPortStatistics.builder(); |
| |
| nicBuilder.setDeviceId(deviceId) |
| .setPort(port) |
| .setPacketsReceived(rxCount) |
| .setPacketsSent(txCount) |
| .setBytesReceived(rxBytes) |
| .setBytesSent(txBytes) |
| .setPacketsRxDropped(rxDropped) |
| .setPacketsRxErrors(rxErrors) |
| .setPacketsTxDropped(txDropped) |
| .setPacketsTxErrors(txErrors) |
| .build(); |
| |
| // We have statistics for this NIC |
| nicStats.add(nicBuilder.build()); |
| } |
| |
| return nicStats; |
| } |
| |
| /** |
| * Parse the input JSON object, looking for timing-related |
| * statistics. Upon success, construct and return a |
| * timing statistics object. |
| * |
| * @param objNode input JSON node with timing statistics information |
| * @return TimingStatistics object or null |
| */ |
| private TimingStatistics parseTimingStatistics(JsonNode objNode) { |
| TimingStatistics timinsgStats = null; |
| |
| if (objNode == null) { |
| return timinsgStats; |
| } |
| |
| // Get timing statistics |
| JsonNode timingNode = objNode.path(PARAM_TIMING_STATS); |
| ObjectNode timingObjNode = (ObjectNode) timingNode; |
| |
| // Time (ns) to parse the controller's deployment instruction |
| long parsingTime = timingObjNode.path(TIMING_PARAM_PARSE).asLong(); |
| // Time (ns) to do the deployment |
| long launchingTime = timingObjNode.path(TIMING_PARAM_LAUNCH).asLong(); |
| // Total time (ns) |
| long totalTime = parsingTime + launchingTime; |
| |
| // Get autoscale timing statistics |
| JsonNode autoscaleTimingNode = objNode.path(PARAM_TIMING_AUTOSCALE); |
| ObjectNode autoscaleTimingObjNode = (ObjectNode) autoscaleTimingNode; |
| |
| // Time (ns) to autoscale a server's load |
| long autoscaleTime = autoscaleTimingObjNode.path( |
| TIMING_PARAM_AUTOSCALE |
| ).asLong(); |
| |
| DefaultTimingStatistics.Builder timingBuilder = |
| DefaultTimingStatistics.builder(); |
| |
| timingBuilder.setParsingTime(parsingTime) |
| .setLaunchingTime(launchingTime) |
| .setAutoscaleTime(autoscaleTime) |
| .build(); |
| |
| return timingBuilder.build(); |
| } |
| |
| /** |
| * Return a timing statistics object with zero counters. |
| * This is useful when constructing MonitoringStatistics |
| * objects that do not require timers. |
| * |
| * @return TimingStatistics object |
| */ |
| private TimingStatistics getZeroTimingStatistics() { |
| DefaultTimingStatistics.Builder zeroTimingBuilder = |
| DefaultTimingStatistics.builder(); |
| |
| zeroTimingBuilder.setParsingTime(0) |
| .setLaunchingTime(0) |
| .setAutoscaleTime(0) |
| .build(); |
| |
| return zeroTimingBuilder.build(); |
| } |
| |
| } |