blob: 346c8ca96570205b4a0d3bdc4154b23855467a3d [file] [log] [blame]
Georgios Katsikas83600982017-05-28 20:41:45 +02001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.drivers.server;
18
19import org.onosproject.drivers.server.behavior.CpuStatisticsDiscovery;
20import org.onosproject.drivers.server.behavior.MonitoringStatisticsDiscovery;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010021import org.onosproject.drivers.server.devices.cpu.CpuCacheHierarchyDevice;
22import org.onosproject.drivers.server.devices.cpu.CpuDevice;
23import org.onosproject.drivers.server.devices.memory.MemoryHierarchyDevice;
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +020024import org.onosproject.drivers.server.devices.nic.NicDevice;
Georgios Katsikas83600982017-05-28 20:41:45 +020025import org.onosproject.drivers.server.devices.ServerDeviceDescription;
26import org.onosproject.drivers.server.devices.RestServerSBDevice;
27import org.onosproject.drivers.server.stats.CpuStatistics;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010028import org.onosproject.drivers.server.stats.MemoryStatistics;
Georgios Katsikas83600982017-05-28 20:41:45 +020029import org.onosproject.drivers.server.stats.MonitoringStatistics;
30import org.onosproject.drivers.server.stats.TimingStatistics;
31
Georgios Katsikas13ccba62020-03-18 12:05:03 +010032import org.onosproject.drivers.server.impl.devices.DefaultBasicCpuCacheDevice;
33import org.onosproject.drivers.server.impl.devices.DefaultCpuCacheHierarchyDevice;
Georgios Katsikas83600982017-05-28 20:41:45 +020034import org.onosproject.drivers.server.impl.devices.DefaultCpuDevice;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010035import org.onosproject.drivers.server.impl.devices.DefaultMemoryHierarchyDevice;
36import org.onosproject.drivers.server.impl.devices.DefaultMemoryModuleDevice;
Georgios Katsikas83600982017-05-28 20:41:45 +020037import org.onosproject.drivers.server.impl.devices.DefaultNicDevice;
38import org.onosproject.drivers.server.impl.devices.DefaultRestServerSBDevice;
39import org.onosproject.drivers.server.impl.devices.DefaultServerDeviceDescription;
40import org.onosproject.drivers.server.impl.stats.DefaultCpuStatistics;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010041import org.onosproject.drivers.server.impl.stats.DefaultMemoryStatistics;
Georgios Katsikas83600982017-05-28 20:41:45 +020042import org.onosproject.drivers.server.impl.stats.DefaultMonitoringStatistics;
43import org.onosproject.drivers.server.impl.stats.DefaultTimingStatistics;
44
45import org.onlab.packet.ChassisId;
46import org.onosproject.net.AnnotationKeys;
47import org.onosproject.net.Device;
48import org.onosproject.net.DeviceId;
49import org.onosproject.net.DefaultAnnotations;
50import org.onosproject.net.behaviour.DevicesDiscovery;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010051import org.onosproject.net.behaviour.DeviceCpuStats;
52import org.onosproject.net.behaviour.DeviceMemoryStats;
53import org.onosproject.net.behaviour.DeviceSystemStatisticsQuery;
54import org.onosproject.net.behaviour.DeviceSystemStats;
Georgios Katsikas83600982017-05-28 20:41:45 +020055import org.onosproject.net.device.DeviceDescription;
56import org.onosproject.net.device.DeviceDescriptionDiscovery;
57import org.onosproject.net.device.DefaultPortStatistics;
58import org.onosproject.net.device.DefaultPortDescription;
59import org.onosproject.net.device.PortDescription;
60import org.onosproject.net.device.PortStatistics;
61import org.onosproject.net.device.PortStatisticsDiscovery;
Georgios Katsikas83600982017-05-28 20:41:45 +020062import org.onosproject.net.PortNumber;
63import org.onosproject.protocol.rest.RestSBDevice;
Georgios Katsikas83600982017-05-28 20:41:45 +020064
65import org.slf4j.Logger;
66
67import com.fasterxml.jackson.core.type.TypeReference;
68import com.fasterxml.jackson.databind.JsonNode;
69import com.fasterxml.jackson.databind.ObjectMapper;
70import com.fasterxml.jackson.databind.node.ObjectNode;
71
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +020072import com.google.common.base.Strings;
Georgios Katsikas83600982017-05-28 20:41:45 +020073import com.google.common.collect.Lists;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010074import com.google.common.collect.Sets;
Georgios Katsikas83600982017-05-28 20:41:45 +020075import com.google.common.collect.ImmutableList;
76
Georgios Katsikas83600982017-05-28 20:41:45 +020077import java.io.InputStream;
78import java.io.IOException;
79import java.net.URI;
80import java.net.URISyntaxException;
81import java.util.ArrayList;
82import java.util.Collection;
83import java.util.Collections;
84import java.util.HashSet;
Georgios Katsikas83600982017-05-28 20:41:45 +020085import java.util.List;
86import java.util.Map;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010087import java.util.Optional;
Georgios Katsikas83600982017-05-28 20:41:45 +020088import java.util.Set;
89import java.util.TreeSet;
Georgios Katsikasc699e872019-05-01 23:26:40 +020090import javax.ws.rs.ProcessingException;
Georgios Katsikas83600982017-05-28 20:41:45 +020091
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +020092import static com.google.common.base.Preconditions.checkArgument;
Georgios Katsikas83600982017-05-28 20:41:45 +020093import static com.google.common.base.Preconditions.checkNotNull;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010094import static org.onosproject.drivers.server.Constants.JSON;
95import static org.onosproject.drivers.server.Constants.MSG_DEVICE_NULL;
96import static org.onosproject.drivers.server.Constants.MSG_DEVICE_ID_NULL;
97import static org.onosproject.drivers.server.Constants.MSG_NIC_NAME_NULL;
98import static org.onosproject.drivers.server.Constants.MSG_NIC_PORT_NUMBER_NEGATIVE;
99import static org.onosproject.drivers.server.Constants.MSG_STATS_TIMING_DEPLOY_INCONSISTENT;
100import static org.onosproject.drivers.server.Constants.PARAM_ID;
101import static org.onosproject.drivers.server.Constants.PARAM_CAPACITY;
102import static org.onosproject.drivers.server.Constants.PARAM_CHASSIS_ID;
103import static org.onosproject.drivers.server.Constants.PARAM_CPUS;
104import static org.onosproject.drivers.server.Constants.PARAM_NICS;
105import static org.onosproject.drivers.server.Constants.PARAM_NAME;
106import static org.onosproject.drivers.server.Constants.PARAM_MEMORY;
107import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_HIERARCHY;
108import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_MODULES;
109import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_STATS_FREE;
110import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_STATS_TOTAL;
111import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_STATS_USED;
112import static org.onosproject.drivers.server.Constants.PARAM_MANUFACTURER;
113import static org.onosproject.drivers.server.Constants.PARAM_HW_VENDOR;
114import static org.onosproject.drivers.server.Constants.PARAM_SW_VENDOR;
115import static org.onosproject.drivers.server.Constants.PARAM_SERIAL;
116import static org.onosproject.drivers.server.Constants.PARAM_TIMING_STATS;
117import static org.onosproject.drivers.server.Constants.PARAM_TIMING_STATS_AUTOSCALE;
118import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_LEVEL;
119import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_LEVELS;
120import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_LINE_LEN;
121import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_POLICY;
122import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_SETS;
123import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_SHARED;
124import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_TYPE;
125import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_WAYS;
126import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHES;
127import static org.onosproject.drivers.server.Constants.PARAM_CPU_CACHE_HIERARCHY;
128import static org.onosproject.drivers.server.Constants.PARAM_CPU_CORES;
129import static org.onosproject.drivers.server.Constants.PARAM_CPU_FREQUENCY;
130import static org.onosproject.drivers.server.Constants.PARAM_CPU_ID_LOG;
131import static org.onosproject.drivers.server.Constants.PARAM_CPU_ID_PHY;
132import static org.onosproject.drivers.server.Constants.PARAM_CPU_LOAD;
133import static org.onosproject.drivers.server.Constants.PARAM_CPU_LATENCY;
134import static org.onosproject.drivers.server.Constants.PARAM_CPU_QUEUE;
135import static org.onosproject.drivers.server.Constants.PARAM_CPU_SOCKET;
136import static org.onosproject.drivers.server.Constants.PARAM_CPU_SOCKETS;
137import static org.onosproject.drivers.server.Constants.PARAM_CPU_STATUS;
138import static org.onosproject.drivers.server.Constants.PARAM_CPU_THROUGHPUT;
139import static org.onosproject.drivers.server.Constants.PARAM_CPU_VENDOR;
140import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_WIDTH_DATA;
141import static org.onosproject.drivers.server.Constants.PARAM_MEMORY_WIDTH_TOTAL;
142import static org.onosproject.drivers.server.Constants.PARAM_NIC_HW_ADDR;
143import static org.onosproject.drivers.server.Constants.PARAM_NIC_PORT_TYPE;
144import static org.onosproject.drivers.server.Constants.PARAM_NIC_RX_FILTER;
145import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_RX_COUNT;
146import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_RX_BYTES;
147import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_RX_DROPS;
148import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_RX_ERRORS;
149import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_TX_COUNT;
150import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_TX_BYTES;
151import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_TX_DROPS;
152import static org.onosproject.drivers.server.Constants.PARAM_NIC_STATS_TX_ERRORS;
153import static org.onosproject.drivers.server.Constants.PARAM_MON_AVERAGE;
154import static org.onosproject.drivers.server.Constants.PARAM_MON_BUSY_CPUS;
155import static org.onosproject.drivers.server.Constants.PARAM_MON_FREE_CPUS;
156import static org.onosproject.drivers.server.Constants.PARAM_MON_MAX;
157import static org.onosproject.drivers.server.Constants.PARAM_MON_MIN;
158import static org.onosproject.drivers.server.Constants.PARAM_MON_UNIT;
159import static org.onosproject.drivers.server.Constants.PARAM_SPEED;
160import static org.onosproject.drivers.server.Constants.PARAM_SPEED_CONF;
161import static org.onosproject.drivers.server.Constants.PARAM_STATUS;
162import static org.onosproject.drivers.server.Constants.PARAM_TIMING_PARSE;
163import static org.onosproject.drivers.server.Constants.PARAM_TIMING_LAUNCH;
164import static org.onosproject.drivers.server.Constants.PARAM_TIMING_DEPLOY;
165import static org.onosproject.drivers.server.Constants.PARAM_TIMING_AUTOSCALE;
166import static org.onosproject.drivers.server.Constants.PARAM_TYPE;
167import static org.onosproject.drivers.server.Constants.SLASH;
168import static org.onosproject.drivers.server.Constants.URL_SRV_GLOBAL_STATS;
169import static org.onosproject.drivers.server.Constants.URL_SRV_RESOURCE_DISCOVERY;
170import static org.onosproject.drivers.server.Constants.URL_SERVICE_CHAINS_STATS;
Georgios Katsikas83600982017-05-28 20:41:45 +0200171import static org.slf4j.LoggerFactory.getLogger;
172
173/**
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100174 * Discovers the device details of server devices.
Georgios Katsikas83600982017-05-28 20:41:45 +0200175 */
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100176public class ServerDevicesDiscovery
177 extends BasicServerDriver
Georgios Katsikas83600982017-05-28 20:41:45 +0200178 implements DevicesDiscovery, DeviceDescriptionDiscovery,
179 PortStatisticsDiscovery, CpuStatisticsDiscovery,
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100180 MonitoringStatisticsDiscovery, DeviceSystemStatisticsQuery {
Georgios Katsikas83600982017-05-28 20:41:45 +0200181
182 private final Logger log = getLogger(getClass());
183
184 /**
Georgios Katsikas83600982017-05-28 20:41:45 +0200185 * Auxiliary constants.
186 */
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100187 private static final short DISCOVERY_RETRIES = 3;
Georgios Katsikas83600982017-05-28 20:41:45 +0200188
189 /**
190 * Constructs server device discovery.
191 */
192 public ServerDevicesDiscovery() {
193 super();
194 log.debug("Started");
195 }
196
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100197 /**
198 * Implements DevicesDiscovery behaviour.
199 */
Georgios Katsikas83600982017-05-28 20:41:45 +0200200 @Override
201 public Set<DeviceId> deviceIds() {
202 // Set of devices to return
203 Set<DeviceId> devices = new HashSet<DeviceId>();
204
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100205 DeviceId deviceId = getDeviceId();
206 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200207 devices.add(deviceId);
208
209 return devices;
210 }
211
212 @Override
213 public DeviceDescription deviceDetails(DeviceId deviceId) {
214 return getDeviceDetails(deviceId);
215 }
216
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100217 /**
218 * Implements DeviceDescriptionDiscovery behaviour.
219 */
Georgios Katsikas83600982017-05-28 20:41:45 +0200220 @Override
221 public DeviceDescription discoverDeviceDetails() {
222 return getDeviceDetails(null);
223 }
224
225 /**
226 * Query a server to retrieve its features.
227 *
228 * @param deviceId the device ID to be queried
229 * @return a DeviceDescription with the device's features
230 */
231 private DeviceDescription getDeviceDetails(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200232 // Retrieve the device ID, if null given
233 if (deviceId == null) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100234 deviceId = getDeviceId();
235 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200236 }
237
238 // Get the device
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100239 RestSBDevice device = getDevice(deviceId);
240 checkNotNull(device, MSG_DEVICE_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200241
242 // Hit the path that provides the server's resources
243 InputStream response = null;
244 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100245 response = getController().get(deviceId, URL_SRV_RESOURCE_DISCOVERY, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200246 } catch (ProcessingException pEx) {
247 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200248 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200249 }
250
251 // Load the JSON into objects
252 ObjectMapper mapper = new ObjectMapper();
253 Map<String, Object> jsonMap = null;
254 JsonNode jsonNode = null;
255 ObjectNode objNode = null;
256 try {
257 jsonMap = mapper.readValue(response, Map.class);
258 jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
259 objNode = (ObjectNode) jsonNode;
260 } catch (IOException ioEx) {
261 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200262 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200263 }
264
265 if (jsonMap == null) {
266 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200267 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200268 }
269
270 // Get all the attributes
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100271 String id = get(jsonNode, PARAM_ID);
272 String vendor = get(jsonNode, PARAM_MANUFACTURER);
273 String hw = get(jsonNode, PARAM_HW_VENDOR);
274 String sw = get(jsonNode, PARAM_SW_VENDOR);
275 String serial = get(jsonNode, PARAM_SERIAL);
276 long chassisId = objNode.path(PARAM_CHASSIS_ID).asLong();
Georgios Katsikas83600982017-05-28 20:41:45 +0200277
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100278 // Pass the southbound protocol as an annotation
279 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
280 annotations.set(AnnotationKeys.PROTOCOL, "REST");
281
282 // Parse CPU devices
283 Collection<CpuDevice> cpuSet = parseCpuDevices(objNode);
284
285 // Parse memory hierarchy device
286 MemoryHierarchyDevice memHierarchyDev = parseMemoryHierarchyDevice(objNode);
287
288 // Parse CPU cache hierachy device
289 CpuCacheHierarchyDevice cacheHierarchyDev = parseCpuCacheHierarchyDevice(objNode);
290
291 // NICs are composite attributes too
292 Collection<NicDevice> nicSet = parseNicDevices(mapper, objNode, annotations);
293
294 // Construct a server device,
295 // i.e., a RestSBDevice extended with CPU, cache, memory, and NIC information
296 RestServerSBDevice dev = new DefaultRestServerSBDevice(
297 device.ip(), device.port(), device.username(),
298 device.password(), device.protocol(), device.url(),
299 device.isActive(), device.testUrl().orElse(""),
300 vendor, hw, sw, cpuSet, cacheHierarchyDev,
301 memHierarchyDev, nicSet);
302 checkNotNull(dev, MSG_DEVICE_NULL);
303
304 // Set alive
305 raiseDeviceReconnect(dev);
306
307 // Updates the controller with the complete device information
308 getController().removeDevice(deviceId);
309 getController().addDevice((RestSBDevice) dev);
310
311 // Create a description for this server device
312 ServerDeviceDescription desc = null;
313 try {
314 desc = new DefaultServerDeviceDescription(
315 new URI(id), Device.Type.SERVER, vendor,
316 hw, sw, serial, new ChassisId(chassisId),
317 cpuSet, cacheHierarchyDev, memHierarchyDev,
318 nicSet, annotations.build());
319 } catch (URISyntaxException uEx) {
320 log.error("Failed to create a server device description for: {}",
321 deviceId);
322 return null;
323 }
324
325 log.info("Device's {} details sent to the controller", deviceId);
326
327 return desc;
328 }
329
330 /**
331 * Parse the input JSON object, looking for CPU-related
332 * information. Upon success, construct and return a list
333 * of CPU devices.
334 *
335 * @param objNode input JSON node with CPU device information
336 * @return list of CPU devices
337 */
338 private Collection<CpuDevice> parseCpuDevices(ObjectNode objNode) {
339 Collection<CpuDevice> cpuSet = Sets.newHashSet();
340 JsonNode cpuNode = objNode.path(PARAM_CPUS);
Georgios Katsikas83600982017-05-28 20:41:45 +0200341
342 // Construct CPU objects
343 for (JsonNode cn : cpuNode) {
344 ObjectNode cpuObjNode = (ObjectNode) cn;
345
346 // All the CPU attributes
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100347 int physicalCpuId = cpuObjNode.path(PARAM_CPU_ID_PHY).asInt();
348 int logicalCpuId = cpuObjNode.path(PARAM_CPU_ID_LOG).asInt();
349 int cpuSocket = cpuObjNode.path(PARAM_CPU_SOCKET).asInt();
350 String cpuVendorStr = get(cn, PARAM_CPU_VENDOR);
351 long cpuFrequency = cpuObjNode.path(PARAM_CPU_FREQUENCY).asLong();
Georgios Katsikas83600982017-05-28 20:41:45 +0200352
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100353 // Construct a CPU device and add it to the set
354 cpuSet.add(
355 DefaultCpuDevice.builder()
356 .setCoreId(logicalCpuId, physicalCpuId)
357 .setVendor(cpuVendorStr)
358 .setSocket(cpuSocket)
359 .setFrequency(cpuFrequency)
360 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +0200361 }
362
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100363 return cpuSet;
364 }
365
366 /**
367 * Parse the input JSON object, looking for CPU cache-related
368 * information. Upon success, construct and return a CPU cache
369 * hierarchy device.
370 *
371 * @param objNode input JSON node with CPU cache device information
372 * @return a CPU cache hierarchy devices
373 */
374 private CpuCacheHierarchyDevice parseCpuCacheHierarchyDevice(ObjectNode objNode) {
375 JsonNode cacheHierarchyNode = objNode.path(PARAM_CPU_CACHE_HIERARCHY);
376 ObjectNode cacheHierarchyObjNode = (ObjectNode) cacheHierarchyNode;
377 if (cacheHierarchyObjNode == null) {
378 return null;
379 }
380
381 int socketsNb = cacheHierarchyObjNode.path(PARAM_CPU_SOCKETS).asInt();
382 int coresNb = cacheHierarchyObjNode.path(PARAM_CPU_CORES).asInt();
383 int levels = cacheHierarchyObjNode.path(PARAM_CPU_CACHE_LEVELS).asInt();
384
385 JsonNode cacheNode = cacheHierarchyObjNode.path(PARAM_CPU_CACHES);
386
387 DefaultCpuCacheHierarchyDevice.Builder cacheBuilder =
388 DefaultCpuCacheHierarchyDevice.builder()
389 .setSocketsNumber(socketsNb)
390 .setCoresNumber(coresNb)
391 .setLevels(levels);
392
393 // Construct CPU cache objects
394 for (JsonNode cn : cacheNode) {
395 ObjectNode cacheObjNode = (ObjectNode) cn;
396
397 // CPU cache attributes
398 String cpuVendorStr = get(cn, PARAM_CPU_VENDOR);
399 String levelStr = get(cn, PARAM_CPU_CACHE_LEVEL);
400 String typeStr = get(cn, PARAM_CPU_CACHE_TYPE);
401 String policyStr = get(cn, PARAM_CPU_CACHE_POLICY);
402 long capacity = cacheObjNode.path(PARAM_CAPACITY).asLong();
403 int sets = cacheObjNode.path(PARAM_CPU_CACHE_SETS).asInt();
404 int ways = cacheObjNode.path(PARAM_CPU_CACHE_WAYS).asInt();
405 int lineLen = cacheObjNode.path(PARAM_CPU_CACHE_LINE_LEN).asInt();
406 boolean shared = cacheObjNode.path(PARAM_CPU_CACHE_SHARED).asInt() > 0;
407
408 // Construct a basic CPU cache device and add it to the hierarchy
409 cacheBuilder.addBasicCpuCacheDevice(
410 DefaultBasicCpuCacheDevice.builder()
411 .setVendor(cpuVendorStr)
412 .setCacheId(levelStr, typeStr)
413 .setPolicy(policyStr)
414 .setCapacity(capacity)
415 .setNumberOfSets(sets)
416 .setNumberOfWays(ways)
417 .setLineLength(lineLen)
418 .isShared(shared)
419 .build());
420 }
421
422 return cacheBuilder.build();
423 }
424
425 /**
426 * Parse the input JSON object, looking for memory-related
427 * information. Upon success, construct and return a memory
428 * hierarchy device.
429 *
430 * @param objNode input JSON node with memory device information
431 * @return a memory hierarchy device
432 */
433 private MemoryHierarchyDevice parseMemoryHierarchyDevice(ObjectNode objNode) {
434 JsonNode memHierarchyNode = objNode.path(PARAM_MEMORY_HIERARCHY);
435 ObjectNode memoryHierarchyObjNode = (ObjectNode) memHierarchyNode;
436 if (memoryHierarchyObjNode == null) {
437 return null;
438 }
439
440 JsonNode memoryNode = memoryHierarchyObjNode.path(PARAM_MEMORY_MODULES);
441
442 DefaultMemoryHierarchyDevice.Builder memoryBuilder =
443 DefaultMemoryHierarchyDevice.builder();
444
445 // Construct memory modules
446 for (JsonNode mn : memoryNode) {
447 ObjectNode memoryObjNode = (ObjectNode) mn;
448
449 String typeStr = get(mn, PARAM_TYPE);
450 String manufacturerStr = get(mn, PARAM_MANUFACTURER);
451 String serialStr = get(mn, PARAM_SERIAL);
452 int dataWidth = memoryObjNode.path(PARAM_MEMORY_WIDTH_DATA).asInt();
453 int totalWidth = memoryObjNode.path(PARAM_MEMORY_WIDTH_TOTAL).asInt();
454 long capacity = memoryObjNode.path(PARAM_CAPACITY).asLong();
455 long speed = memoryObjNode.path(PARAM_SPEED).asLong();
456 long configuredSpeed = memoryObjNode.path(PARAM_SPEED_CONF).asLong();
457
458 // Construct a memory module and add it to the hierarchy
459 memoryBuilder.addMemoryModule(
460 DefaultMemoryModuleDevice.builder()
461 .setType(typeStr)
462 .setManufacturer(manufacturerStr)
463 .setSerialNumber(serialStr)
464 .setDataWidth(dataWidth)
465 .setTotalWidth(totalWidth)
466 .setCapacity(capacity)
467 .setSpeed(speed)
468 .setConfiguredSpeed(configuredSpeed)
469 .build());
470 }
471
472 return memoryBuilder.build();
473 }
474
475 /**
476 * Parse the input JSON object, looking for NIC-related
477 * information. Upon success, construct and return a list
478 * of NIC devices.
479 *
480 * @param mapper input JSON object mapper
481 * @param objNode input JSON node with NIC device information
482 * @param annotations device annotations
483 * @return list of CPU devices
484 */
485 private Collection<NicDevice> parseNicDevices(
486 ObjectMapper mapper, ObjectNode objNode, DefaultAnnotations.Builder annotations) {
487 Collection<NicDevice> nicSet = Sets.newHashSet();
Georgios Katsikas83600982017-05-28 20:41:45 +0200488 JsonNode nicNode = objNode.path(PARAM_NICS);
489
490 // Construct NIC objects
491 for (JsonNode nn : nicNode) {
492 ObjectNode nicObjNode = (ObjectNode) nn;
493
494 // All the NIC attributes
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100495 String nicName = get(nn, PARAM_NAME);
496 long nicIndex = nicObjNode.path(PARAM_ID).asLong();
497 long speed = nicObjNode.path(PARAM_SPEED).asLong();
498 String portTypeStr = get(nn, PARAM_NIC_PORT_TYPE);
499 boolean status = nicObjNode.path(PARAM_STATUS).asInt() > 0;
500 String hwAddr = get(nn, PARAM_NIC_HW_ADDR);
501 JsonNode tagNode = nicObjNode.path(PARAM_NIC_RX_FILTER);
Georgios Katsikas83600982017-05-28 20:41:45 +0200502 if (tagNode == null) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800503 throw new IllegalArgumentException(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200504 "The Rx filters of NIC " + nicName + " are not reported");
Georgios Katsikas83600982017-05-28 20:41:45 +0200505 }
506
507 // Convert the JSON list into an array of strings
508 List<String> rxFilters = null;
509 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200510 rxFilters = mapper.readValue(tagNode.traverse(),
511 new TypeReference<ArrayList<String>>() { });
Georgios Katsikas83600982017-05-28 20:41:45 +0200512 } catch (IOException ioEx) {
513 continue;
514 }
515
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200516 // Store NIC name to number mapping as an annotation
517 annotations.set(nicName, Long.toString(nicIndex));
518
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100519 // Construct a NIC device and add it to the set
520 nicSet.add(
521 DefaultNicDevice.builder()
522 .setName(nicName)
523 .setPortNumber(nicIndex)
524 .setPortNumber(nicIndex)
525 .setPortType(portTypeStr)
526 .setSpeed(speed)
527 .setStatus(status)
528 .setMacAddress(hwAddr)
529 .setRxFilters(rxFilters)
530 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +0200531 }
532
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100533 return nicSet;
Georgios Katsikas83600982017-05-28 20:41:45 +0200534 }
535
536 @Override
537 public List<PortDescription> discoverPortDetails() {
Georgios Katsikas83600982017-05-28 20:41:45 +0200538 // Retrieve the device ID
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100539 DeviceId deviceId = getDeviceId();
540 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200541
Georgios Katsikas83600982017-05-28 20:41:45 +0200542 // .. and object
543 RestServerSBDevice device = null;
Georgios Katsikas30bede52018-07-28 14:46:07 +0200544 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100545 device = (RestServerSBDevice) getDevice(deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200546 } catch (ClassCastException ccEx) {
547 log.error("Failed to discover ports for device {}", deviceId);
548 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200549 }
550
Georgios Katsikas30bede52018-07-28 14:46:07 +0200551 if (device == null) {
552 log.error("No device with ID {} is available for port discovery", deviceId);
553 return Collections.EMPTY_LIST;
554 }
555 if ((device.nics() == null) || (device.nics().size() == 0)) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200556 log.error("No ports available on {}", deviceId);
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200557 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200558 }
559
Georgios Katsikas30bede52018-07-28 14:46:07 +0200560 // List of port descriptions to return
561 List<PortDescription> portDescriptions = Lists.newArrayList();
562
Georgios Katsikas83600982017-05-28 20:41:45 +0200563 // Sorted list of NIC ports
564 Set<NicDevice> nics = new TreeSet(device.nics());
565
566 // Iterate through the NICs of this device to populate the list
Georgios Katsikas83600982017-05-28 20:41:45 +0200567 for (NicDevice nic : nics) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200568 // Include the name of this device as an annotation
569 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200570 .set(AnnotationKeys.PORT_NAME, nic.name());
Georgios Katsikas83600982017-05-28 20:41:45 +0200571
572 // Create a port description and add it to the list
573 portDescriptions.add(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800574 DefaultPortDescription.builder()
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100575 // CHECK: .withPortNumber(PortNumber.portNumber(nic.portNumber(), nic.name()))
576 .withPortNumber(PortNumber.portNumber(nic.portNumber()))
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800577 .isEnabled(nic.status())
578 .type(nic.portType())
579 .portSpeed(nic.speed())
580 .annotations(annotations.build())
581 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +0200582
Georgios Katsikasd472a322018-07-08 19:58:25 +0200583 log.info("Port discovery on device {}: NIC {} is {} at {} Mbps",
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200584 deviceId, nic.portNumber(), nic.status() ? "up" : "down",
Georgios Katsikasd472a322018-07-08 19:58:25 +0200585 nic.speed());
Georgios Katsikas83600982017-05-28 20:41:45 +0200586 }
587
588 return ImmutableList.copyOf(portDescriptions);
589 }
590
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100591 /**
592 * Implements PortStatisticsDiscovery behaviour.
593 */
Georgios Katsikas83600982017-05-28 20:41:45 +0200594 @Override
595 public Collection<PortStatistics> discoverPortStatistics() {
596 // Retrieve the device ID
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100597 DeviceId deviceId = getDeviceId();
598 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200599
600 // Get port statistics for this device
601 return getPortStatistics(deviceId);
602 }
603
604 /**
605 * Query a server to retrieve its port statistics.
606 *
607 * @param deviceId the device ID to be queried
608 * @return list of (per port) PortStatistics
609 */
610 private Collection<PortStatistics> getPortStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200611 // Get global monitoring statistics
612 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
613 if (monStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200614 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200615 }
616
617 // Filter out the NIC statistics
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200618 Collection<PortStatistics> portStats = monStats.nicStatisticsAll();
Georgios Katsikas83600982017-05-28 20:41:45 +0200619 if (portStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200620 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200621 }
622
623 log.debug("Port statistics: {}", portStats.toString());
624
625 return portStats;
626 }
627
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100628 /**
629 * Implements CpuStatisticsDiscovery behaviour.
630 */
Georgios Katsikas83600982017-05-28 20:41:45 +0200631 @Override
632 public Collection<CpuStatistics> discoverCpuStatistics() {
633 // Retrieve the device ID
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100634 DeviceId deviceId = getDeviceId();
635 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200636
637 // Get CPU statistics for this device
638 return getCpuStatistics(deviceId);
639 }
640
641 /**
642 * Query a server to retrieve its CPU statistics.
643 *
644 * @param deviceId the device ID to be queried
645 * @return list of (per core) CpuStatistics
646 */
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200647 public Collection<CpuStatistics> getCpuStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200648 // Get global monitoring statistics
649 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
650 if (monStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200651 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200652 }
653
654 // Filter out the CPU statistics
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200655 Collection<CpuStatistics> cpuStats = monStats.cpuStatisticsAll();
Georgios Katsikas83600982017-05-28 20:41:45 +0200656 if (cpuStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200657 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200658 }
659
660 log.debug("CPU statistics: {}", cpuStats.toString());
661
662 return cpuStats;
663 }
664
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100665 /**
666 * Implements MonitoringStatisticsDiscovery behaviour.
667 */
Georgios Katsikas83600982017-05-28 20:41:45 +0200668 @Override
669 public MonitoringStatistics discoverGlobalMonitoringStatistics() {
670 // Retrieve the device ID
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100671 DeviceId deviceId = getDeviceId();
672 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200673
674 // Get global monitoring statistics for this device
675 return getGlobalMonitoringStatistics(deviceId);
676 }
677
678 /**
679 * Query a server to retrieve its global monitoring statistics.
680 *
681 * @param deviceId the device ID to be queried
682 * @return global monitoring statistics
683 */
Georgios Katsikasfda66742018-07-31 20:18:14 +0200684 public MonitoringStatistics getGlobalMonitoringStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200685 // Monitoring statistics to return
686 MonitoringStatistics monStats = null;
687
688 RestServerSBDevice device = null;
689 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100690 device = (RestServerSBDevice) getDevice(deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200691 } catch (ClassCastException ccEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200692 log.error("Failed to retrieve global monitoring statistics from device {}",
693 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200694 return monStats;
695 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200696 if ((device == null) || (!device.isActive())) {
697 return monStats;
698 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200699
700 // Hit the path that provides the server's global resources
701 InputStream response = null;
702 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100703 response = getController().get(deviceId, URL_SRV_GLOBAL_STATS, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200704 } catch (ProcessingException pEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200705 log.error("Failed to retrieve global monitoring statistics from device {}",
706 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200707 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200708 return monStats;
709 }
710
711 // Load the JSON into objects
712 ObjectMapper mapper = new ObjectMapper();
713 Map<String, Object> jsonMap = null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200714 ObjectNode objNode = null;
715 try {
716 jsonMap = mapper.readValue(response, Map.class);
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200717 JsonNode jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
Georgios Katsikas83600982017-05-28 20:41:45 +0200718 objNode = (ObjectNode) jsonNode;
719 } catch (IOException ioEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200720 log.error("Failed to retrieve global monitoring statistics from device {}",
721 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200722 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200723 return monStats;
724 }
725
726 if (jsonMap == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200727 log.error("Failed to retrieve global monitoring statistics from device {}",
728 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200729 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200730 return monStats;
731 }
732
733 // Get high-level CPU statistics
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100734 int busyCpus = objNode.path(PARAM_MON_BUSY_CPUS).asInt();
735 int freeCpus = objNode.path(PARAM_MON_FREE_CPUS).asInt();
Georgios Katsikas83600982017-05-28 20:41:45 +0200736
737 // Get a list of CPU statistics per core
738 Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode);
739
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100740 // Get main memory statistics
741 MemoryStatistics memStats = parseMemoryStatistics(deviceId, objNode);
742
Georgios Katsikas83600982017-05-28 20:41:45 +0200743 // Get a list of port statistics
744 Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode);
745
746 // Get zero timing statistics
747 TimingStatistics timinsgStats = getZeroTimingStatistics();
748
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100749 // Construct a global monitoring statistics object out of smaller ones
750 monStats = DefaultMonitoringStatistics.builder()
751 .setDeviceId(deviceId)
752 .setTimingStatistics(timinsgStats)
753 .setCpuStatistics(cpuStats)
754 .setMemoryStatistics(memStats)
755 .setNicStatistics(nicStats)
756 .build();
Georgios Katsikas83600982017-05-28 20:41:45 +0200757
Georgios Katsikasfda66742018-07-31 20:18:14 +0200758 // When a device reports monitoring data, it means it is alive
759 raiseDeviceReconnect(device);
760
Georgios Katsikas83600982017-05-28 20:41:45 +0200761 log.debug("Global monitoring statistics: {}", monStats.toString());
762
763 return monStats;
764 }
765
766 @Override
767 public MonitoringStatistics discoverMonitoringStatistics(URI tcId) {
768 // Retrieve the device ID
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100769 DeviceId deviceId = getDeviceId();
770 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +0200771
772 // Get resource-specific monitoring statistics for this device
773 return getMonitoringStatistics(deviceId, tcId);
774 }
775
776 /**
777 * Query a server to retrieve monitoring statistics for a
778 * specific resource (i.e., traffic class).
779 *
780 * @param deviceId the device ID to be queried
781 * @param tcId the ID of the traffic class to be monitored
782 * @return resource-specific monitoring statistics
783 */
784 private MonitoringStatistics getMonitoringStatistics(DeviceId deviceId, URI tcId) {
785 // Monitoring statistics to return
786 MonitoringStatistics monStats = null;
787
788 RestServerSBDevice device = null;
789 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100790 device = (RestServerSBDevice) getDevice(deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200791 } catch (ClassCastException ccEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200792 log.error("Failed to retrieve monitoring statistics from device {}",
793 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200794 return monStats;
795 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200796 if (device == null) {
797 return monStats;
798 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200799
800 // Create a resource-specific URL
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100801 String scUrl = URL_SERVICE_CHAINS_STATS + SLASH + tcId.toString();
Georgios Katsikas83600982017-05-28 20:41:45 +0200802
803 // Hit the path that provides the server's specific resources
804 InputStream response = null;
805 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200806 response = getController().get(deviceId, scUrl, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200807 } catch (ProcessingException pEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200808 log.error("Failed to retrieve monitoring statistics from device {}",
809 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200810 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200811 return monStats;
812 }
813
814 // Load the JSON into objects
815 ObjectMapper mapper = new ObjectMapper();
816 Map<String, Object> jsonMap = null;
817 JsonNode jsonNode = null;
818 ObjectNode objNode = null;
819 try {
820 jsonMap = mapper.readValue(response, Map.class);
821 jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
822 objNode = (ObjectNode) jsonNode;
823 } catch (IOException ioEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200824 log.error("Failed to retrieve monitoring statistics from device {}",
825 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200826 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200827 return monStats;
828 }
829
830 if (jsonMap == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200831 log.error("Failed to retrieve monitoring statistics from device {}",
832 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200833 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200834 return monStats;
835 }
836
837 // Get the ID of the traffic class
838 String id = get(jsonNode, PARAM_ID);
839
840 // And verify that this is the traffic class we want to monitor
841 if (!id.equals(tcId.toString())) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800842 throw new IllegalStateException(
Georgios Katsikas83600982017-05-28 20:41:45 +0200843 "Failed to retrieve monitoring data for traffic class " + tcId +
844 ". Traffic class ID does not agree."
845 );
846 }
847
848 // Get a list of CPU statistics per core
849 Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode);
850
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100851 // Get main memory statistics
852 MemoryStatistics memStats = parseMemoryStatistics(deviceId, objNode);
853
Georgios Katsikas83600982017-05-28 20:41:45 +0200854 // Get a list of port statistics
855 Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode);
856
857 // Get timing statistics
858 TimingStatistics timinsgStats = parseTimingStatistics(objNode);
859
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100860 // Construct a global monitoring statistics object out of smaller ones
861 monStats = DefaultMonitoringStatistics.builder()
862 .setDeviceId(deviceId)
863 .setTimingStatistics(timinsgStats)
864 .setCpuStatistics(cpuStats)
865 .setMemoryStatistics(memStats)
866 .setNicStatistics(nicStats)
867 .build();
Georgios Katsikas83600982017-05-28 20:41:45 +0200868
Georgios Katsikasfda66742018-07-31 20:18:14 +0200869 // When a device reports monitoring data, it means it is alive
870 raiseDeviceReconnect(device);
871
Georgios Katsikas83600982017-05-28 20:41:45 +0200872 log.debug("Monitoring statistics: {}", monStats.toString());
873
874 return monStats;
875 }
876
877 /**
878 * Parse the input JSON object, looking for CPU-related
879 * statistics. Upon success, construct and return a list
880 * of CPU statistics objects.
881 *
882 * @param deviceId the device ID that sent the JSON object
883 * @param objNode input JSON node with CPU statistics information
884 * @return list of (per core) CpuStatistics
885 */
Georgios Katsikas30bede52018-07-28 14:46:07 +0200886 private Collection<CpuStatistics> parseCpuStatistics(DeviceId deviceId, JsonNode objNode) {
887 if ((deviceId == null) || (objNode == null)) {
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200888 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200889 }
890
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200891 Collection<CpuStatistics> cpuStats = Lists.newArrayList();
892
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100893 JsonNode cpuNode = objNode.path(PARAM_CPUS);
Georgios Katsikas83600982017-05-28 20:41:45 +0200894
895 for (JsonNode cn : cpuNode) {
896 ObjectNode cpuObjNode = (ObjectNode) cn;
897
Georgios Katsikasfda66742018-07-31 20:18:14 +0200898 // CPU statistics builder
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100899 DefaultCpuStatistics.Builder cpuStatsBuilder = DefaultCpuStatistics.builder();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200900
901 // Throughput statistics are optional
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100902 JsonNode throughputNode = cpuObjNode.get(PARAM_CPU_THROUGHPUT);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200903 if (throughputNode != null) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100904 String throughputUnit = get(throughputNode, PARAM_MON_UNIT);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200905 if (!Strings.isNullOrEmpty(throughputUnit)) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100906 cpuStatsBuilder.setThroughputUnit(throughputUnit);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200907 }
908 float averageThroughput = (float) 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100909 if (throughputNode.get(PARAM_MON_AVERAGE) != null) {
910 averageThroughput = throughputNode.path(PARAM_MON_AVERAGE).floatValue();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200911 }
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100912 cpuStatsBuilder.setAverageThroughput(averageThroughput);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200913 }
914
915 // Latency statistics are optional
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100916 JsonNode latencyNode = cpuObjNode.get(PARAM_CPU_LATENCY);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200917 if (latencyNode != null) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100918 String latencyUnit = get(latencyNode, PARAM_MON_UNIT);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200919 if (!Strings.isNullOrEmpty(latencyUnit)) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100920 cpuStatsBuilder.setLatencyUnit(latencyUnit);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200921 }
922 float minLatency = (float) 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100923 if (latencyNode.get(PARAM_MON_MIN) != null) {
924 minLatency = latencyNode.path(PARAM_MON_MIN).floatValue();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200925 }
Georgios Katsikas973a2652018-06-28 08:45:47 +0200926 float averageLatency = (float) 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100927 if (latencyNode.get(PARAM_MON_AVERAGE) != null) {
928 averageLatency = latencyNode.path(PARAM_MON_AVERAGE).floatValue();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200929 }
930 float maxLatency = (float) 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100931 if (latencyNode.get(PARAM_MON_MAX) != null) {
932 maxLatency = latencyNode.path(PARAM_MON_MAX).floatValue();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200933 }
934
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100935 cpuStatsBuilder.setMinLatency(minLatency)
Georgios Katsikas973a2652018-06-28 08:45:47 +0200936 .setAverageLatency(averageLatency)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200937 .setMaxLatency(maxLatency);
938 }
939
Georgios Katsikas83600982017-05-28 20:41:45 +0200940 // CPU ID with its load and status
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100941 int cpuId = cpuObjNode.path(PARAM_ID).asInt();
942 float cpuLoad = cpuObjNode.path(PARAM_CPU_LOAD).floatValue();
943 int queueId = cpuObjNode.path(PARAM_CPU_QUEUE).asInt();
944 int busySince = cpuObjNode.path(PARAM_CPU_STATUS).asInt();
Georgios Katsikas83600982017-05-28 20:41:45 +0200945
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100946 // We have all the statistics for this CPU core
947 cpuStats.add(
948 cpuStatsBuilder
949 .setDeviceId(deviceId)
Georgios Katsikas83600982017-05-28 20:41:45 +0200950 .setId(cpuId)
951 .setLoad(cpuLoad)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200952 .setQueue(queueId)
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100953 .setBusySince(busySince)
954 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +0200955 }
956
957 return cpuStats;
958 }
959
960 /**
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100961 * Parse the input JSON object, looking for memory-related
962 * statistics. Upon success, construct and return a memory
963 * statistics objects.
964 *
965 * @param deviceId the device ID that sent the JSON object
966 * @param objNode input JSON node with memory statistics information
967 * @return memory statistics object
968 */
969 private MemoryStatistics parseMemoryStatistics(DeviceId deviceId, JsonNode objNode) {
970 if ((deviceId == null) || (objNode == null)) {
971 return null;
972 }
973
974 JsonNode memoryNode = objNode.path(PARAM_MEMORY);
975 ObjectNode memoryObjNode = (ObjectNode) memoryNode;
976
977 // Fetch memory statistics
978 String unit = get(memoryNode, PARAM_MON_UNIT);
979 long used = memoryObjNode.path(PARAM_MEMORY_STATS_USED).asLong();
980 long free = memoryObjNode.path(PARAM_MEMORY_STATS_FREE).asLong();
981 long total = memoryObjNode.path(PARAM_MEMORY_STATS_TOTAL).asLong();
982
983 // Memory statistics builder
984 return DefaultMemoryStatistics.builder()
985 .setDeviceId(deviceId)
986 .setMemoryUsed(used)
987 .setMemoryFree(free)
988 .setMemoryTotal(total)
989 .build();
990 }
991
992 /**
Georgios Katsikas83600982017-05-28 20:41:45 +0200993 * Parse the input JSON object, looking for NIC-related
994 * statistics. Upon success, construct and return a list
995 * of NIC statistics objects.
996 *
997 * @param deviceId the device ID that sent the JSON object
998 * @param objNode input JSON node with NIC statistics information
999 * @return list of (per port) PortStatistics
1000 */
Georgios Katsikas30bede52018-07-28 14:46:07 +02001001 private Collection<PortStatistics> parseNicStatistics(DeviceId deviceId, JsonNode objNode) {
1002 if ((deviceId == null) || (objNode == null)) {
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +02001003 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +02001004 }
1005
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +02001006 RestServerSBDevice device = null;
1007 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001008 device = (RestServerSBDevice) getDevice(deviceId);
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +02001009 } catch (ClassCastException ccEx) {
1010 return Collections.EMPTY_LIST;
1011 }
Georgios Katsikas30bede52018-07-28 14:46:07 +02001012 if (device == null) {
1013 return Collections.EMPTY_LIST;
1014 }
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +02001015
1016 Collection<PortStatistics> nicStats = Lists.newArrayList();
1017
Georgios Katsikas83600982017-05-28 20:41:45 +02001018 JsonNode nicNode = objNode.path(PARAM_NICS);
1019
1020 for (JsonNode nn : nicNode) {
1021 ObjectNode nicObjNode = (ObjectNode) nn;
1022
1023 // All the NIC attributes
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001024 String nicName = get(nn, PARAM_NAME);
1025 checkArgument(!Strings.isNullOrEmpty(nicName), MSG_NIC_NAME_NULL);
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +02001026
1027 long portNumber = device.portNumberFromName(nicName);
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001028 checkArgument(portNumber >= 0, MSG_NIC_PORT_NUMBER_NEGATIVE);
Georgios Katsikas83600982017-05-28 20:41:45 +02001029
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001030 long rxCount = nicObjNode.path(PARAM_NIC_STATS_RX_COUNT).asLong();
1031 long rxBytes = nicObjNode.path(PARAM_NIC_STATS_RX_BYTES).asLong();
1032 long rxDropped = nicObjNode.path(PARAM_NIC_STATS_RX_DROPS).asLong();
1033 long rxErrors = nicObjNode.path(PARAM_NIC_STATS_RX_ERRORS).asLong();
1034 long txCount = nicObjNode.path(PARAM_NIC_STATS_TX_COUNT).asLong();
1035 long txBytes = nicObjNode.path(PARAM_NIC_STATS_TX_BYTES).asLong();
1036 long txDropped = nicObjNode.path(PARAM_NIC_STATS_TX_DROPS).asLong();
1037 long txErrors = nicObjNode.path(PARAM_NIC_STATS_TX_ERRORS).asLong();
Georgios Katsikas83600982017-05-28 20:41:45 +02001038
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001039 // Construct a NIC statistics object and add it to the set
1040 nicStats.add(
1041 DefaultPortStatistics.builder()
1042 .setDeviceId(deviceId)
Ray Milkey5ec42082019-02-13 09:56:07 -08001043 .setPort(PortNumber.portNumber(portNumber))
Georgios Katsikas83600982017-05-28 20:41:45 +02001044 .setPacketsReceived(rxCount)
1045 .setPacketsSent(txCount)
1046 .setBytesReceived(rxBytes)
1047 .setBytesSent(txBytes)
1048 .setPacketsRxDropped(rxDropped)
1049 .setPacketsRxErrors(rxErrors)
1050 .setPacketsTxDropped(txDropped)
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001051 .setPacketsTxErrors(txErrors)
1052 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +02001053 }
1054
1055 return nicStats;
1056 }
1057
1058 /**
Georgios Katsikasfda66742018-07-31 20:18:14 +02001059 * Parse the input JSON object, looking for timing-related statistics.
1060 * Upon success, return a timing statistics object with the advertized values.
1061 * Upon failure, return a timing statistics object with zero-initialized values.
Georgios Katsikas83600982017-05-28 20:41:45 +02001062 *
1063 * @param objNode input JSON node with timing statistics information
1064 * @return TimingStatistics object or null
1065 */
1066 private TimingStatistics parseTimingStatistics(JsonNode objNode) {
1067 TimingStatistics timinsgStats = null;
1068
1069 if (objNode == null) {
1070 return timinsgStats;
1071 }
1072
Georgios Katsikasfda66742018-07-31 20:18:14 +02001073 // If no timing statistics are present, then send zeros
1074 if (objNode.get(PARAM_TIMING_STATS) == null) {
1075 return getZeroTimingStatistics();
1076 }
1077
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001078 DefaultTimingStatistics.Builder timingBuilder =
1079 DefaultTimingStatistics.builder();
Georgios Katsikasfda66742018-07-31 20:18:14 +02001080
Georgios Katsikas83600982017-05-28 20:41:45 +02001081 // Get timing statistics
1082 JsonNode timingNode = objNode.path(PARAM_TIMING_STATS);
1083 ObjectNode timingObjNode = (ObjectNode) timingNode;
1084
Georgios Katsikasfda66742018-07-31 20:18:14 +02001085 // The unit of timing statistics
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001086 String timingStatsUnit = get(timingNode, PARAM_MON_UNIT);
Georgios Katsikasfda66742018-07-31 20:18:14 +02001087 if (!Strings.isNullOrEmpty(timingStatsUnit)) {
1088 timingBuilder.setUnit(timingStatsUnit);
1089 }
1090
Georgios Katsikas83600982017-05-28 20:41:45 +02001091 // Time (ns) to parse the controller's deployment instruction
Georgios Katsikasfda66742018-07-31 20:18:14 +02001092 long parsingTime = 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001093 if (timingObjNode.get(PARAM_TIMING_PARSE) != null) {
1094 parsingTime = timingObjNode.path(PARAM_TIMING_PARSE).asLong();
Georgios Katsikasfda66742018-07-31 20:18:14 +02001095 }
Georgios Katsikas83600982017-05-28 20:41:45 +02001096 // Time (ns) to do the deployment
Georgios Katsikasfda66742018-07-31 20:18:14 +02001097 long launchingTime = 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001098 if (timingObjNode.get(PARAM_TIMING_LAUNCH) != null) {
1099 launchingTime = timingObjNode.path(PARAM_TIMING_LAUNCH).asLong();
Georgios Katsikasfda66742018-07-31 20:18:14 +02001100 }
1101 // Deployment time (ns) equals to time to parse + time to launch
1102 long deployTime = 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001103 if (timingObjNode.get(PARAM_TIMING_DEPLOY) != null) {
1104 deployTime = timingObjNode.path(PARAM_TIMING_DEPLOY).asLong();
Georgios Katsikasfda66742018-07-31 20:18:14 +02001105 }
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001106 checkArgument(deployTime == parsingTime + launchingTime,
1107 MSG_STATS_TIMING_DEPLOY_INCONSISTENT);
Georgios Katsikasfda66742018-07-31 20:18:14 +02001108
1109 timingBuilder.setParsingTime(parsingTime)
1110 .setLaunchingTime(launchingTime);
Georgios Katsikas83600982017-05-28 20:41:45 +02001111
1112 // Get autoscale timing statistics
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001113 JsonNode autoscaleTimingNode = objNode.path(PARAM_TIMING_STATS_AUTOSCALE);
Georgios Katsikasfda66742018-07-31 20:18:14 +02001114 if (autoscaleTimingNode == null) {
1115 return timingBuilder.build();
1116 }
1117
Georgios Katsikas973a2652018-06-28 08:45:47 +02001118 ObjectNode autoScaleTimingObjNode = (ObjectNode) autoscaleTimingNode;
Georgios Katsikas83600982017-05-28 20:41:45 +02001119 // Time (ns) to autoscale a server's load
Georgios Katsikas973a2652018-06-28 08:45:47 +02001120 long autoScaleTime = 0;
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001121 if (autoScaleTimingObjNode.get(PARAM_TIMING_AUTOSCALE) != null) {
1122 autoScaleTime = autoScaleTimingObjNode.path(PARAM_TIMING_AUTOSCALE).asLong();
Georgios Katsikasfda66742018-07-31 20:18:14 +02001123 }
Georgios Katsikas973a2652018-06-28 08:45:47 +02001124 timingBuilder.setAutoScaleTime(autoScaleTime);
Georgios Katsikas83600982017-05-28 20:41:45 +02001125
1126 return timingBuilder.build();
1127 }
1128
1129 /**
1130 * Return a timing statistics object with zero counters.
1131 * This is useful when constructing MonitoringStatistics
1132 * objects that do not require timers.
1133 *
1134 * @return TimingStatistics object
1135 */
1136 private TimingStatistics getZeroTimingStatistics() {
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001137 return DefaultTimingStatistics.builder()
1138 .setParsingTime(0)
1139 .setLaunchingTime(0)
1140 .setAutoScaleTime(0)
1141 .build();
1142 }
Georgios Katsikas83600982017-05-28 20:41:45 +02001143
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001144 /**
1145 * Implements DeviceSystemStatisticsQuery behaviour.
1146 */
1147 @Override
1148 public Optional<DeviceSystemStats> getDeviceSystemStats() {
1149 // Retrieve the device ID from the handler
1150 DeviceId deviceId = getDeviceId();
1151 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas83600982017-05-28 20:41:45 +02001152
Georgios Katsikas13ccba62020-03-18 12:05:03 +01001153 // ....to retrieve monitoring statistics
1154 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
1155
1156 Optional<DeviceCpuStats> cpuStats = getOverallCpuUsage(monStats);
1157 Optional<DeviceMemoryStats> memoryStats = getOverallMemoryUsage(monStats);
1158
1159 if (cpuStats.isPresent() && memoryStats.isPresent()) {
1160 return Optional.of(new DeviceSystemStats(memoryStats.get(), cpuStats.get()));
1161 } else {
1162 return Optional.empty();
1163 }
1164 }
1165
1166 /**
1167 * Get CPU usage of server device.
1168 *
1169 * @param monStats global monitoring statistics which contain CPU statistics
1170 * @return cpuStats, device CPU usage stats if available
1171 */
1172 private Optional<DeviceCpuStats> getOverallCpuUsage(MonitoringStatistics monStats) {
1173 if (monStats == null) {
1174 return Optional.empty();
1175 }
1176
1177 if (monStats.numberOfCpus() == 0) {
1178 return Optional.of(new DeviceCpuStats());
1179 }
1180
1181 float usedCpu = 0.0f;
1182 for (CpuStatistics cpuCoreStats : monStats.cpuStatisticsAll()) {
1183 if (cpuCoreStats.busy()) {
1184 usedCpu += cpuCoreStats.load();
1185 }
1186 }
1187
1188 return Optional.of(new DeviceCpuStats(usedCpu / (float) monStats.numberOfCpus()));
1189 }
1190
1191 /**
1192 * Get memory usage of server device in KB.
1193 *
1194 * @param monStats global monitoring statistics which contain memory statistics
1195 * @return memoryStats, device memory usage stats if available
1196 */
1197 private Optional<DeviceMemoryStats> getOverallMemoryUsage(MonitoringStatistics monStats) {
1198 if (monStats == null) {
1199 return Optional.empty();
1200 }
1201
1202 MemoryStatistics memStats = monStats.memoryStatistics();
1203
1204 return Optional.of(
1205 new DeviceMemoryStats(memStats.free(), memStats.used(), memStats.total()));
Georgios Katsikas83600982017-05-28 20:41:45 +02001206 }
1207
1208}