blob: d52f1158315f4ce1524d443e647b0004d53abdd1 [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;
21import org.onosproject.drivers.server.devices.CpuDevice;
22import org.onosproject.drivers.server.devices.CpuVendor;
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +020023import org.onosproject.drivers.server.devices.nic.NicDevice;
24import org.onosproject.drivers.server.devices.nic.NicRxFilter;
25import org.onosproject.drivers.server.devices.nic.NicRxFilter.RxFilter;
Georgios Katsikas83600982017-05-28 20:41:45 +020026import org.onosproject.drivers.server.devices.ServerDeviceDescription;
27import org.onosproject.drivers.server.devices.RestServerSBDevice;
28import org.onosproject.drivers.server.stats.CpuStatistics;
29import org.onosproject.drivers.server.stats.MonitoringStatistics;
30import org.onosproject.drivers.server.stats.TimingStatistics;
31
32import org.onosproject.drivers.server.impl.devices.DefaultCpuDevice;
33import org.onosproject.drivers.server.impl.devices.DefaultNicDevice;
34import org.onosproject.drivers.server.impl.devices.DefaultRestServerSBDevice;
35import org.onosproject.drivers.server.impl.devices.DefaultServerDeviceDescription;
36import org.onosproject.drivers.server.impl.stats.DefaultCpuStatistics;
37import org.onosproject.drivers.server.impl.stats.DefaultMonitoringStatistics;
38import org.onosproject.drivers.server.impl.stats.DefaultTimingStatistics;
39
40import org.onlab.packet.ChassisId;
41import org.onosproject.net.AnnotationKeys;
42import org.onosproject.net.Device;
43import org.onosproject.net.DeviceId;
44import org.onosproject.net.DefaultAnnotations;
45import org.onosproject.net.behaviour.DevicesDiscovery;
46import org.onosproject.net.device.DeviceDescription;
47import org.onosproject.net.device.DeviceDescriptionDiscovery;
48import org.onosproject.net.device.DefaultPortStatistics;
49import org.onosproject.net.device.DefaultPortDescription;
50import org.onosproject.net.device.PortDescription;
51import org.onosproject.net.device.PortStatistics;
52import org.onosproject.net.device.PortStatisticsDiscovery;
53import org.onosproject.net.Port;
54import org.onosproject.net.PortNumber;
55import org.onosproject.protocol.rest.RestSBDevice;
56import org.onosproject.protocol.rest.RestSBDevice.AuthenticationScheme;
57
58import org.slf4j.Logger;
59
60import com.fasterxml.jackson.core.type.TypeReference;
61import com.fasterxml.jackson.databind.JsonNode;
62import com.fasterxml.jackson.databind.ObjectMapper;
63import com.fasterxml.jackson.databind.node.ObjectNode;
64
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +020065import com.google.common.base.Strings;
Georgios Katsikas83600982017-05-28 20:41:45 +020066import com.google.common.collect.Lists;
67import com.google.common.collect.ImmutableList;
68
69import javax.ws.rs.ProcessingException;
70import java.io.InputStream;
71import java.io.IOException;
72import java.net.URI;
73import java.net.URISyntaxException;
74import java.util.ArrayList;
75import java.util.Collection;
76import java.util.Collections;
77import java.util.HashSet;
78import java.util.HashMap;
79import java.util.List;
80import java.util.Map;
81import java.util.Set;
82import java.util.TreeSet;
83
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +020084import static com.google.common.base.Preconditions.checkArgument;
Georgios Katsikas83600982017-05-28 20:41:45 +020085import static com.google.common.base.Preconditions.checkNotNull;
86import static org.slf4j.LoggerFactory.getLogger;
87
88/**
89 * Discovers the device details of
90 * REST-based commodity server devices.
91 */
92public class ServerDevicesDiscovery extends BasicServerDriver
93 implements DevicesDiscovery, DeviceDescriptionDiscovery,
94 PortStatisticsDiscovery, CpuStatisticsDiscovery,
95 MonitoringStatisticsDiscovery {
96
97 private final Logger log = getLogger(getClass());
98
99 /**
100 * Resource endpoints of the server agent (REST server-side).
101 */
Georgios Katsikas30bede52018-07-28 14:46:07 +0200102 private static final String RESOURCE_DISCOVERY_URL = BASE_URL + SLASH + "resources";
103 private static final String GLOBAL_STATS_URL = BASE_URL + SLASH + "stats";
104 private static final String SERVICE_CHAINS_STATS_URL = BASE_URL + SLASH + "chains_stats"; // + /ID
Georgios Katsikas83600982017-05-28 20:41:45 +0200105
106 /**
107 * Parameters to be exchanged with the server's agent.
108 */
Georgios Katsikas83600982017-05-28 20:41:45 +0200109 private static final String PARAM_MANUFACTURER = "manufacturer";
110 private static final String PARAM_HW_VENDOR = "hwVersion";
111 private static final String PARAM_SW_VENDOR = "swVersion";
112 private static final String PARAM_SERIAL = "serial";
Georgios Katsikasfda66742018-07-31 20:18:14 +0200113 private static final String PARAM_TIMING_STATS = "timingStats";
114 private static final String PARAM_TIMING_AUTOSCALE = "autoScaleTimingStats";
Georgios Katsikas83600982017-05-28 20:41:45 +0200115
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200116 private static final String NIC_PARAM_NAME = "name";
117 private static final String NIC_PARAM_PORT_INDEX = "index";
Georgios Katsikas83600982017-05-28 20:41:45 +0200118 private static final String NIC_PARAM_PORT_TYPE = "portType";
119 private static final String NIC_PARAM_PORT_TYPE_FIBER = "fiber";
120 private static final String NIC_PARAM_PORT_TYPE_COPPER = "copper";
121 private static final String NIC_PARAM_SPEED = "speed";
122 private static final String NIC_PARAM_STATUS = "status";
123 private static final String NIC_PARAM_HW_ADDR = "hwAddr";
Georgios Katsikas83600982017-05-28 20:41:45 +0200124
125 /**
126 * NIC statistics.
127 */
128 private static final String NIC_STATS_TX_COUNT = "txCount";
129 private static final String NIC_STATS_TX_BYTES = "txBytes";
130 private static final String NIC_STATS_TX_DROPS = "txDropped";
131 private static final String NIC_STATS_TX_ERRORS = "txErrors";
132 private static final String NIC_STATS_RX_COUNT = "rxCount";
133 private static final String NIC_STATS_RX_BYTES = "rxBytes";
134 private static final String NIC_STATS_RX_DROPS = "rxDropped";
135 private static final String NIC_STATS_RX_ERRORS = "rxErrors";
136
137 /**
138 * CPU statistics.
139 */
Georgios Katsikasfda66742018-07-31 20:18:14 +0200140 private static final String CPU_PARAM_ID = "id";
141 private static final String CPU_PARAM_VENDOR = "vendor";
142 private static final String CPU_PARAM_FREQUENCY = "frequency";
143 private static final String CPU_PARAM_LOAD = "load";
144 private static final String CPU_PARAM_QUEUE = "queue";
145 private static final String CPU_PARAM_STATUS = "busy";
146 private static final String CPU_PARAM_THROUGHPUT = "throughput";
147 private static final String CPU_PARAM_LATENCY = "latency";
148 private static final String MON_PARAM_UNIT = "unit";
149 private static final String MON_PARAM_BUSY_CPUS = "busyCpus";
150 private static final String MON_PARAM_FREE_CPUS = "freeCpus";
151 private static final String MON_PARAM_MIN = "min";
152 private static final String MON_PARAM_AVERAGE = "average";
153 private static final String MON_PARAM_MEDIAN = "median";
154 private static final String MON_PARAM_MAX = "max";
Georgios Katsikas83600982017-05-28 20:41:45 +0200155
156 /**
157 * Timing statistics.
158 */
Georgios Katsikasfda66742018-07-31 20:18:14 +0200159 private static final String TIMING_PARAM_PARSE = "parseTime";
160 private static final String TIMING_PARAM_LAUNCH = "launchTime";
161 private static final String TIMING_PARAM_DEPLOY = "deployTime";
162 private static final String TIMING_PARAM_AUTOSCALE = "autoScaleTime";
Georgios Katsikas83600982017-05-28 20:41:45 +0200163
164 /**
165 * Auxiliary constants.
166 */
167 private static final short DISCOVERY_RETRIES = 3;
168 private static final String CPU_VENDOR_NULL = "Unsupported CPU vendor" +
169 " Choose one in: " + BasicServerDriver.enumTypesToString(CpuVendor.class);
170 private static final String NIC_RX_FILTER_NULL = "Unsupported NIC Rx filter" +
171 " Choose one in: " + BasicServerDriver.enumTypesToString(RxFilter.class);
172
173 /**
174 * Port types that usually appear in commodity servers.
175 */
176 public static final Map<String, Port.Type> PORT_TYPE_MAP =
177 Collections.unmodifiableMap(
178 new HashMap<String, Port.Type>() {
179 {
180 put(NIC_PARAM_PORT_TYPE_FIBER, Port.Type.FIBER);
181 put(NIC_PARAM_PORT_TYPE_COPPER, Port.Type.COPPER);
182 }
183 }
184 );
185
186 /**
187 * Constructs server device discovery.
188 */
189 public ServerDevicesDiscovery() {
190 super();
191 log.debug("Started");
192 }
193
194 @Override
195 public Set<DeviceId> deviceIds() {
196 // Set of devices to return
197 Set<DeviceId> devices = new HashSet<DeviceId>();
198
199 DeviceId deviceId = getHandler().data().deviceId();
200 checkNotNull(deviceId, DEVICE_ID_NULL);
201 devices.add(deviceId);
202
203 return devices;
204 }
205
206 @Override
207 public DeviceDescription deviceDetails(DeviceId deviceId) {
208 return getDeviceDetails(deviceId);
209 }
210
211 @Override
212 public DeviceDescription discoverDeviceDetails() {
213 return getDeviceDetails(null);
214 }
215
216 /**
217 * Query a server to retrieve its features.
218 *
219 * @param deviceId the device ID to be queried
220 * @return a DeviceDescription with the device's features
221 */
222 private DeviceDescription getDeviceDetails(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200223 // Retrieve the device ID, if null given
224 if (deviceId == null) {
225 deviceId = getHandler().data().deviceId();
226 checkNotNull(deviceId, DEVICE_ID_NULL);
227 }
228
229 // Get the device
230 RestSBDevice device = getController().getDevice(deviceId);
231 checkNotNull(device, DEVICE_NULL);
232
233 // Hit the path that provides the server's resources
234 InputStream response = null;
235 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200236 response = getController().get(deviceId, RESOURCE_DISCOVERY_URL, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200237 } catch (ProcessingException pEx) {
238 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200239 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200240 }
241
242 // Load the JSON into objects
243 ObjectMapper mapper = new ObjectMapper();
244 Map<String, Object> jsonMap = null;
245 JsonNode jsonNode = null;
246 ObjectNode objNode = null;
247 try {
248 jsonMap = mapper.readValue(response, Map.class);
249 jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
250 objNode = (ObjectNode) jsonNode;
251 } catch (IOException ioEx) {
252 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200253 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200254 }
255
256 if (jsonMap == null) {
257 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200258 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200259 }
260
261 // Get all the attributes
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200262 String id = get(jsonNode, BasicServerDriver.PARAM_ID);
Georgios Katsikas83600982017-05-28 20:41:45 +0200263 String vendor = get(jsonNode, PARAM_MANUFACTURER);
264 String hw = get(jsonNode, PARAM_HW_VENDOR);
265 String sw = get(jsonNode, PARAM_SW_VENDOR);
266 String serial = get(jsonNode, PARAM_SERIAL);
267
268 // CPUs are composite attributes
269 Set<CpuDevice> cpuSet = new HashSet<CpuDevice>();
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200270 JsonNode cpuNode = objNode.path(BasicServerDriver.PARAM_CPUS);
Georgios Katsikas83600982017-05-28 20:41:45 +0200271
272 // Construct CPU objects
273 for (JsonNode cn : cpuNode) {
274 ObjectNode cpuObjNode = (ObjectNode) cn;
275
276 // All the CPU attributes
277 int cpuId = cpuObjNode.path(CPU_PARAM_ID).asInt();
278 String cpuVendorStr = get(cn, CPU_PARAM_VENDOR);
279 long cpuFrequency = cpuObjNode.path(CPU_PARAM_FREQUENCY).asLong();
280
281 // Verify that this is a valid vendor
282 CpuVendor cpuVendor = CpuVendor.getByName(cpuVendorStr);
283 checkNotNull(cpuVendor, CPU_VENDOR_NULL);
284
285 // Construct a CPU device
286 CpuDevice cpu = new DefaultCpuDevice(cpuId, cpuVendor, cpuFrequency);
287
288 // Add it to the set
289 cpuSet.add(cpu);
290 }
291
292 // NICs are composite attributes too
293 Set<NicDevice> nicSet = new HashSet<NicDevice>();
294 JsonNode nicNode = objNode.path(PARAM_NICS);
295
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200296 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
297
Georgios Katsikas83600982017-05-28 20:41:45 +0200298 // Construct NIC objects
299 for (JsonNode nn : nicNode) {
300 ObjectNode nicObjNode = (ObjectNode) nn;
301
302 // All the NIC attributes
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200303 String nicName = get(nn, NIC_PARAM_NAME);
304 long nicIndex = nicObjNode.path(NIC_PARAM_PORT_INDEX).asLong();
Georgios Katsikas83600982017-05-28 20:41:45 +0200305 long speed = nicObjNode.path(NIC_PARAM_SPEED).asLong();
306 String portTypeStr = get(nn, NIC_PARAM_PORT_TYPE);
307 Port.Type portType = PORT_TYPE_MAP.get(portTypeStr);
308 if (portType == null) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800309 throw new IllegalArgumentException(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200310 portTypeStr + " is not a valid port type for NIC " + nicName);
Georgios Katsikas83600982017-05-28 20:41:45 +0200311 }
312 boolean status = nicObjNode.path(NIC_PARAM_STATUS).asInt() > 0;
313 String hwAddr = get(nn, NIC_PARAM_HW_ADDR);
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200314 JsonNode tagNode = nicObjNode.path(BasicServerDriver.NIC_PARAM_RX_FILTER);
Georgios Katsikas83600982017-05-28 20:41:45 +0200315 if (tagNode == null) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800316 throw new IllegalArgumentException(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200317 "The Rx filters of NIC " + nicName + " are not reported");
Georgios Katsikas83600982017-05-28 20:41:45 +0200318 }
319
320 // Convert the JSON list into an array of strings
321 List<String> rxFilters = null;
322 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200323 rxFilters = mapper.readValue(tagNode.traverse(),
324 new TypeReference<ArrayList<String>>() { });
Georgios Katsikas83600982017-05-28 20:41:45 +0200325 } catch (IOException ioEx) {
326 continue;
327 }
328
329 // Parse the array of strings and create an RxFilter object
330 NicRxFilter rxFilterMechanism = new NicRxFilter();
331 for (String s : rxFilters) {
332 // Verify that this is a valid Rx filter
333 RxFilter rf = RxFilter.getByName(s);
334 checkNotNull(rf, NIC_RX_FILTER_NULL);
335
336 rxFilterMechanism.addRxFilter(rf);
337 }
338
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200339 // Store NIC name to number mapping as an annotation
340 annotations.set(nicName, Long.toString(nicIndex));
341
Georgios Katsikas83600982017-05-28 20:41:45 +0200342 // Construct a NIC device for this server
343 NicDevice nic = new DefaultNicDevice(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200344 nicName, nicIndex, portType, speed, status, hwAddr, rxFilterMechanism);
Georgios Katsikas83600982017-05-28 20:41:45 +0200345
346 // Add it to the set
347 nicSet.add(nic);
348 }
349
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200350 // Construct a complete server device object.
351 // Lists of NICs and CPUs extend the information
352 // already in RestSBDevice (parent class).
Georgios Katsikas83600982017-05-28 20:41:45 +0200353 RestServerSBDevice dev = new DefaultRestServerSBDevice(
354 device.ip(), device.port(), device.username(),
355 device.password(), device.protocol(), device.url(),
356 device.isActive(), device.testUrl().toString(),
357 vendor, hw, sw, AuthenticationScheme.BASIC, "",
358 cpuSet, nicSet
359 );
360 checkNotNull(dev, DEVICE_NULL);
361
Georgios Katsikasfda66742018-07-31 20:18:14 +0200362 // Set alive
363 raiseDeviceReconnect(dev);
364
Georgios Katsikas83600982017-05-28 20:41:45 +0200365 // Updates the controller with the complete device information
366 getController().removeDevice(deviceId);
367 getController().addDevice((RestSBDevice) dev);
368
Georgios Katsikas30bede52018-07-28 14:46:07 +0200369 // Create a description for this server device
370 ServerDeviceDescription desc = null;
371
Georgios Katsikas83600982017-05-28 20:41:45 +0200372 try {
373 desc = new DefaultServerDeviceDescription(
Georgios Katsikas40ecef32018-07-03 11:17:44 +0200374 new URI(id), Device.Type.SERVER, vendor,
Georgios Katsikas83600982017-05-28 20:41:45 +0200375 hw, sw, serial, new ChassisId(),
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200376 cpuSet, nicSet, annotations.build()
Georgios Katsikas83600982017-05-28 20:41:45 +0200377 );
378 } catch (URISyntaxException uEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200379 log.error("Failed to create a server device description for: {}",
380 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200381 return null;
382 }
383
384 log.info("Device's {} details sent to the controller", deviceId);
385
386 return desc;
387 }
388
389 @Override
390 public List<PortDescription> discoverPortDetails() {
Georgios Katsikas83600982017-05-28 20:41:45 +0200391 // Retrieve the device ID
392 DeviceId deviceId = getHandler().data().deviceId();
393 checkNotNull(deviceId, DEVICE_ID_NULL);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200394
Georgios Katsikas83600982017-05-28 20:41:45 +0200395 // .. and object
396 RestServerSBDevice device = null;
Georgios Katsikas30bede52018-07-28 14:46:07 +0200397 try {
398 device = (RestServerSBDevice) getController().getDevice(deviceId);
399 } catch (ClassCastException ccEx) {
400 log.error("Failed to discover ports for device {}", deviceId);
401 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200402 }
403
Georgios Katsikas30bede52018-07-28 14:46:07 +0200404 if (device == null) {
405 log.error("No device with ID {} is available for port discovery", deviceId);
406 return Collections.EMPTY_LIST;
407 }
408 if ((device.nics() == null) || (device.nics().size() == 0)) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200409 log.error("No ports available on {}", deviceId);
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200410 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200411 }
412
Georgios Katsikas30bede52018-07-28 14:46:07 +0200413 // List of port descriptions to return
414 List<PortDescription> portDescriptions = Lists.newArrayList();
415
Georgios Katsikas83600982017-05-28 20:41:45 +0200416 // Sorted list of NIC ports
417 Set<NicDevice> nics = new TreeSet(device.nics());
418
419 // Iterate through the NICs of this device to populate the list
Georgios Katsikas83600982017-05-28 20:41:45 +0200420 for (NicDevice nic : nics) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200421 // Include the name of this device as an annotation
422 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200423 .set(AnnotationKeys.PORT_NAME, nic.name());
Georgios Katsikas83600982017-05-28 20:41:45 +0200424
425 // Create a port description and add it to the list
426 portDescriptions.add(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800427 DefaultPortDescription.builder()
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200428 .withPortNumber(PortNumber.portNumber(nic.portNumber(), nic.name()))
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800429 .isEnabled(nic.status())
430 .type(nic.portType())
431 .portSpeed(nic.speed())
432 .annotations(annotations.build())
433 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +0200434
Georgios Katsikasd472a322018-07-08 19:58:25 +0200435 log.info("Port discovery on device {}: NIC {} is {} at {} Mbps",
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200436 deviceId, nic.portNumber(), nic.status() ? "up" : "down",
Georgios Katsikasd472a322018-07-08 19:58:25 +0200437 nic.speed());
Georgios Katsikas83600982017-05-28 20:41:45 +0200438 }
439
440 return ImmutableList.copyOf(portDescriptions);
441 }
442
443 @Override
444 public Collection<PortStatistics> discoverPortStatistics() {
445 // Retrieve the device ID
446 DeviceId deviceId = getHandler().data().deviceId();
447 checkNotNull(deviceId, DEVICE_ID_NULL);
448
449 // Get port statistics for this device
450 return getPortStatistics(deviceId);
451 }
452
453 /**
454 * Query a server to retrieve its port statistics.
455 *
456 * @param deviceId the device ID to be queried
457 * @return list of (per port) PortStatistics
458 */
459 private Collection<PortStatistics> getPortStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200460 // Get global monitoring statistics
461 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
462 if (monStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200463 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200464 }
465
466 // Filter out the NIC statistics
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200467 Collection<PortStatistics> portStats = monStats.nicStatisticsAll();
Georgios Katsikas83600982017-05-28 20:41:45 +0200468 if (portStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200469 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200470 }
471
472 log.debug("Port statistics: {}", portStats.toString());
473
474 return portStats;
475 }
476
477 @Override
478 public Collection<CpuStatistics> discoverCpuStatistics() {
479 // Retrieve the device ID
480 DeviceId deviceId = getHandler().data().deviceId();
481 checkNotNull(deviceId, DEVICE_ID_NULL);
482
483 // Get CPU statistics for this device
484 return getCpuStatistics(deviceId);
485 }
486
487 /**
488 * Query a server to retrieve its CPU statistics.
489 *
490 * @param deviceId the device ID to be queried
491 * @return list of (per core) CpuStatistics
492 */
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200493 public Collection<CpuStatistics> getCpuStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200494 // Get global monitoring statistics
495 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
496 if (monStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200497 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200498 }
499
500 // Filter out the CPU statistics
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200501 Collection<CpuStatistics> cpuStats = monStats.cpuStatisticsAll();
Georgios Katsikas83600982017-05-28 20:41:45 +0200502 if (cpuStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200503 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200504 }
505
506 log.debug("CPU statistics: {}", cpuStats.toString());
507
508 return cpuStats;
509 }
510
511 @Override
512 public MonitoringStatistics discoverGlobalMonitoringStatistics() {
513 // Retrieve the device ID
514 DeviceId deviceId = getHandler().data().deviceId();
515 checkNotNull(deviceId, DEVICE_ID_NULL);
516
517 // Get global monitoring statistics for this device
518 return getGlobalMonitoringStatistics(deviceId);
519 }
520
521 /**
522 * Query a server to retrieve its global monitoring statistics.
523 *
524 * @param deviceId the device ID to be queried
525 * @return global monitoring statistics
526 */
Georgios Katsikasfda66742018-07-31 20:18:14 +0200527 public MonitoringStatistics getGlobalMonitoringStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200528 // Monitoring statistics to return
529 MonitoringStatistics monStats = null;
530
531 RestServerSBDevice device = null;
532 try {
533 device = (RestServerSBDevice) getController().getDevice(deviceId);
534 } catch (ClassCastException ccEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200535 log.error("Failed to retrieve global monitoring statistics from device {}",
536 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200537 return monStats;
538 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200539 if ((device == null) || (!device.isActive())) {
540 return monStats;
541 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200542
543 // Hit the path that provides the server's global resources
544 InputStream response = null;
545 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200546 response = getController().get(deviceId, GLOBAL_STATS_URL, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200547 } catch (ProcessingException pEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200548 log.error("Failed to retrieve global monitoring statistics from device {}",
549 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200550 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200551 return monStats;
552 }
553
554 // Load the JSON into objects
555 ObjectMapper mapper = new ObjectMapper();
556 Map<String, Object> jsonMap = null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200557 ObjectNode objNode = null;
558 try {
559 jsonMap = mapper.readValue(response, Map.class);
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200560 JsonNode jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
Georgios Katsikas83600982017-05-28 20:41:45 +0200561 objNode = (ObjectNode) jsonNode;
562 } catch (IOException ioEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200563 log.error("Failed to retrieve global monitoring statistics from device {}",
564 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200565 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200566 return monStats;
567 }
568
569 if (jsonMap == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200570 log.error("Failed to retrieve global monitoring statistics from device {}",
571 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200572 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200573 return monStats;
574 }
575
576 // Get high-level CPU statistics
Georgios Katsikasfda66742018-07-31 20:18:14 +0200577 int busyCpus = objNode.path(MON_PARAM_BUSY_CPUS).asInt();
578 int freeCpus = objNode.path(MON_PARAM_FREE_CPUS).asInt();
Georgios Katsikas83600982017-05-28 20:41:45 +0200579
580 // Get a list of CPU statistics per core
581 Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode);
582
583 // Get a list of port statistics
584 Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode);
585
586 // Get zero timing statistics
587 TimingStatistics timinsgStats = getZeroTimingStatistics();
588
589 // Ready to construct the grand object
590 DefaultMonitoringStatistics.Builder statsBuilder =
591 DefaultMonitoringStatistics.builder();
592
593 statsBuilder.setDeviceId(deviceId)
594 .setTimingStatistics(timinsgStats)
595 .setCpuStatistics(cpuStats)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200596 .setNicStatistics(nicStats);
Georgios Katsikas83600982017-05-28 20:41:45 +0200597
598 monStats = statsBuilder.build();
599
Georgios Katsikasfda66742018-07-31 20:18:14 +0200600 // When a device reports monitoring data, it means it is alive
601 raiseDeviceReconnect(device);
602
Georgios Katsikas83600982017-05-28 20:41:45 +0200603 log.debug("Global monitoring statistics: {}", monStats.toString());
604
605 return monStats;
606 }
607
608 @Override
609 public MonitoringStatistics discoverMonitoringStatistics(URI tcId) {
610 // Retrieve the device ID
611 DeviceId deviceId = getHandler().data().deviceId();
612 checkNotNull(deviceId, DEVICE_ID_NULL);
613
614 // Get resource-specific monitoring statistics for this device
615 return getMonitoringStatistics(deviceId, tcId);
616 }
617
618 /**
619 * Query a server to retrieve monitoring statistics for a
620 * specific resource (i.e., traffic class).
621 *
622 * @param deviceId the device ID to be queried
623 * @param tcId the ID of the traffic class to be monitored
624 * @return resource-specific monitoring statistics
625 */
626 private MonitoringStatistics getMonitoringStatistics(DeviceId deviceId, URI tcId) {
627 // Monitoring statistics to return
628 MonitoringStatistics monStats = null;
629
630 RestServerSBDevice device = null;
631 try {
632 device = (RestServerSBDevice) getController().getDevice(deviceId);
633 } catch (ClassCastException ccEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200634 log.error("Failed to retrieve monitoring statistics from device {}",
635 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200636 return monStats;
637 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200638 if (device == null) {
639 return monStats;
640 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200641
642 // Create a resource-specific URL
Georgios Katsikas30bede52018-07-28 14:46:07 +0200643 String scUrl = SERVICE_CHAINS_STATS_URL + SLASH + tcId.toString();
Georgios Katsikas83600982017-05-28 20:41:45 +0200644
645 // Hit the path that provides the server's specific resources
646 InputStream response = null;
647 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200648 response = getController().get(deviceId, scUrl, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200649 } catch (ProcessingException pEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200650 log.error("Failed to retrieve monitoring statistics from device {}",
651 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200652 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200653 return monStats;
654 }
655
656 // Load the JSON into objects
657 ObjectMapper mapper = new ObjectMapper();
658 Map<String, Object> jsonMap = null;
659 JsonNode jsonNode = null;
660 ObjectNode objNode = null;
661 try {
662 jsonMap = mapper.readValue(response, Map.class);
663 jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
664 objNode = (ObjectNode) jsonNode;
665 } catch (IOException ioEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200666 log.error("Failed to retrieve monitoring statistics from device {}",
667 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200668 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200669 return monStats;
670 }
671
672 if (jsonMap == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200673 log.error("Failed to retrieve monitoring statistics from device {}",
674 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200675 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200676 return monStats;
677 }
678
679 // Get the ID of the traffic class
680 String id = get(jsonNode, PARAM_ID);
681
682 // And verify that this is the traffic class we want to monitor
683 if (!id.equals(tcId.toString())) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800684 throw new IllegalStateException(
Georgios Katsikas83600982017-05-28 20:41:45 +0200685 "Failed to retrieve monitoring data for traffic class " + tcId +
686 ". Traffic class ID does not agree."
687 );
688 }
689
690 // Get a list of CPU statistics per core
691 Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode);
692
693 // Get a list of port statistics
694 Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode);
695
696 // Get timing statistics
697 TimingStatistics timinsgStats = parseTimingStatistics(objNode);
698
699 // Ready to construct the grand object
700 DefaultMonitoringStatistics.Builder statsBuilder =
701 DefaultMonitoringStatistics.builder();
702
703 statsBuilder.setDeviceId(deviceId)
704 .setTimingStatistics(timinsgStats)
705 .setCpuStatistics(cpuStats)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200706 .setNicStatistics(nicStats);
Georgios Katsikas83600982017-05-28 20:41:45 +0200707
708 monStats = statsBuilder.build();
709
Georgios Katsikasfda66742018-07-31 20:18:14 +0200710 // When a device reports monitoring data, it means it is alive
711 raiseDeviceReconnect(device);
712
Georgios Katsikas83600982017-05-28 20:41:45 +0200713 log.debug("Monitoring statistics: {}", monStats.toString());
714
715 return monStats;
716 }
717
718 /**
719 * Parse the input JSON object, looking for CPU-related
720 * statistics. Upon success, construct and return a list
721 * of CPU statistics objects.
722 *
723 * @param deviceId the device ID that sent the JSON object
724 * @param objNode input JSON node with CPU statistics information
725 * @return list of (per core) CpuStatistics
726 */
Georgios Katsikas30bede52018-07-28 14:46:07 +0200727 private Collection<CpuStatistics> parseCpuStatistics(DeviceId deviceId, JsonNode objNode) {
728 if ((deviceId == null) || (objNode == null)) {
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200729 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200730 }
731
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200732 Collection<CpuStatistics> cpuStats = Lists.newArrayList();
733
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200734 JsonNode cpuNode = objNode.path(BasicServerDriver.PARAM_CPUS);
Georgios Katsikas83600982017-05-28 20:41:45 +0200735
736 for (JsonNode cn : cpuNode) {
737 ObjectNode cpuObjNode = (ObjectNode) cn;
738
Georgios Katsikasfda66742018-07-31 20:18:14 +0200739 // CPU statistics builder
740 DefaultCpuStatistics.Builder cpuBuilder = DefaultCpuStatistics.builder();
741
742 // Throughput statistics are optional
743 JsonNode throughputNode = cpuObjNode.get(CPU_PARAM_THROUGHPUT);
744 if (throughputNode != null) {
745 String throughputUnit = get(throughputNode, MON_PARAM_UNIT);
746 if (!Strings.isNullOrEmpty(throughputUnit)) {
747 cpuBuilder.setThroughputUnit(throughputUnit);
748 }
749 float averageThroughput = (float) 0;
750 if (throughputNode.get(MON_PARAM_AVERAGE) != null) {
751 averageThroughput = throughputNode.path(MON_PARAM_AVERAGE).floatValue();
752 }
753 cpuBuilder.setAverageThroughput(averageThroughput);
754 }
755
756 // Latency statistics are optional
757 JsonNode latencyNode = cpuObjNode.get(CPU_PARAM_LATENCY);
758 if (latencyNode != null) {
759 String latencyUnit = get(latencyNode, MON_PARAM_UNIT);
760 if (!Strings.isNullOrEmpty(latencyUnit)) {
761 cpuBuilder.setLatencyUnit(latencyUnit);
762 }
763 float minLatency = (float) 0;
764 if (latencyNode.get(MON_PARAM_MIN) != null) {
765 minLatency = latencyNode.path(MON_PARAM_MIN).floatValue();
766 }
767 float medianLatency = (float) 0;
768 if (latencyNode.get(MON_PARAM_MEDIAN) != null) {
769 medianLatency = latencyNode.path(MON_PARAM_MEDIAN).floatValue();
770 }
771 float maxLatency = (float) 0;
772 if (latencyNode.get(MON_PARAM_MAX) != null) {
773 maxLatency = latencyNode.path(MON_PARAM_MAX).floatValue();
774 }
775
776 cpuBuilder.setMinLatency(minLatency)
777 .setMedianLatency(medianLatency)
778 .setMaxLatency(maxLatency);
779 }
780
Georgios Katsikas83600982017-05-28 20:41:45 +0200781 // CPU ID with its load and status
Georgios Katsikasfda66742018-07-31 20:18:14 +0200782 int cpuId = cpuObjNode.path(CPU_PARAM_ID).asInt();
783 float cpuLoad = cpuObjNode.path(CPU_PARAM_LOAD).floatValue();
784 int queueId = cpuObjNode.path(CPU_PARAM_QUEUE).asInt();
Georgios Katsikas83600982017-05-28 20:41:45 +0200785 boolean isBusy = cpuObjNode.path(CPU_PARAM_STATUS).booleanValue();
786
Georgios Katsikasfda66742018-07-31 20:18:14 +0200787 // This is mandatory information
Georgios Katsikas83600982017-05-28 20:41:45 +0200788 cpuBuilder.setDeviceId(deviceId)
789 .setId(cpuId)
790 .setLoad(cpuLoad)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200791 .setQueue(queueId)
792 .setIsBusy(isBusy);
Georgios Katsikas83600982017-05-28 20:41:45 +0200793
Georgios Katsikasfda66742018-07-31 20:18:14 +0200794 // We have all the statistics for this CPU core
Georgios Katsikas83600982017-05-28 20:41:45 +0200795 cpuStats.add(cpuBuilder.build());
796 }
797
798 return cpuStats;
799 }
800
801 /**
802 * Parse the input JSON object, looking for NIC-related
803 * statistics. Upon success, construct and return a list
804 * of NIC statistics objects.
805 *
806 * @param deviceId the device ID that sent the JSON object
807 * @param objNode input JSON node with NIC statistics information
808 * @return list of (per port) PortStatistics
809 */
Georgios Katsikas30bede52018-07-28 14:46:07 +0200810 private Collection<PortStatistics> parseNicStatistics(DeviceId deviceId, JsonNode objNode) {
811 if ((deviceId == null) || (objNode == null)) {
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200812 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200813 }
814
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200815 RestServerSBDevice device = null;
816 try {
817 device = (RestServerSBDevice) getController().getDevice(deviceId);
818 } catch (ClassCastException ccEx) {
819 return Collections.EMPTY_LIST;
820 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200821 if (device == null) {
822 return Collections.EMPTY_LIST;
823 }
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200824
825 Collection<PortStatistics> nicStats = Lists.newArrayList();
826
Georgios Katsikas83600982017-05-28 20:41:45 +0200827 JsonNode nicNode = objNode.path(PARAM_NICS);
828
829 for (JsonNode nn : nicNode) {
830 ObjectNode nicObjNode = (ObjectNode) nn;
831
832 // All the NIC attributes
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200833 String nicName = get(nn, NIC_PARAM_NAME);
834 checkArgument(!Strings.isNullOrEmpty(nicName), "NIC name is empty or NULL");
835
836 long portNumber = device.portNumberFromName(nicName);
837 checkArgument(portNumber >= 0, "Unknown port ID " + portNumber + " for NIC " + nicName);
Georgios Katsikas83600982017-05-28 20:41:45 +0200838
839 long rxCount = nicObjNode.path(NIC_STATS_RX_COUNT).asLong();
840 long rxBytes = nicObjNode.path(NIC_STATS_RX_BYTES).asLong();
841 long rxDropped = nicObjNode.path(NIC_STATS_RX_DROPS).asLong();
842 long rxErrors = nicObjNode.path(NIC_STATS_RX_ERRORS).asLong();
843 long txCount = nicObjNode.path(NIC_STATS_TX_COUNT).asLong();
844 long txBytes = nicObjNode.path(NIC_STATS_TX_BYTES).asLong();
845 long txDropped = nicObjNode.path(NIC_STATS_TX_DROPS).asLong();
846 long txErrors = nicObjNode.path(NIC_STATS_TX_ERRORS).asLong();
847
848 // Incorporate these statistics into an object
Georgios Katsikasfda66742018-07-31 20:18:14 +0200849 DefaultPortStatistics.Builder nicBuilder = DefaultPortStatistics.builder();
Georgios Katsikas83600982017-05-28 20:41:45 +0200850
851 nicBuilder.setDeviceId(deviceId)
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200852 .setPort((int) portNumber)
Georgios Katsikas83600982017-05-28 20:41:45 +0200853 .setPacketsReceived(rxCount)
854 .setPacketsSent(txCount)
855 .setBytesReceived(rxBytes)
856 .setBytesSent(txBytes)
857 .setPacketsRxDropped(rxDropped)
858 .setPacketsRxErrors(rxErrors)
859 .setPacketsTxDropped(txDropped)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200860 .setPacketsTxErrors(txErrors);
Georgios Katsikas83600982017-05-28 20:41:45 +0200861
862 // We have statistics for this NIC
863 nicStats.add(nicBuilder.build());
864 }
865
866 return nicStats;
867 }
868
869 /**
Georgios Katsikasfda66742018-07-31 20:18:14 +0200870 * Parse the input JSON object, looking for timing-related statistics.
871 * Upon success, return a timing statistics object with the advertized values.
872 * Upon failure, return a timing statistics object with zero-initialized values.
Georgios Katsikas83600982017-05-28 20:41:45 +0200873 *
874 * @param objNode input JSON node with timing statistics information
875 * @return TimingStatistics object or null
876 */
877 private TimingStatistics parseTimingStatistics(JsonNode objNode) {
878 TimingStatistics timinsgStats = null;
879
880 if (objNode == null) {
881 return timinsgStats;
882 }
883
Georgios Katsikasfda66742018-07-31 20:18:14 +0200884 // If no timing statistics are present, then send zeros
885 if (objNode.get(PARAM_TIMING_STATS) == null) {
886 return getZeroTimingStatistics();
887 }
888
889 DefaultTimingStatistics.Builder timingBuilder = DefaultTimingStatistics.builder();
890
Georgios Katsikas83600982017-05-28 20:41:45 +0200891 // Get timing statistics
892 JsonNode timingNode = objNode.path(PARAM_TIMING_STATS);
893 ObjectNode timingObjNode = (ObjectNode) timingNode;
894
Georgios Katsikasfda66742018-07-31 20:18:14 +0200895 // The unit of timing statistics
896 String timingStatsUnit = get(timingNode, MON_PARAM_UNIT);
897 if (!Strings.isNullOrEmpty(timingStatsUnit)) {
898 timingBuilder.setUnit(timingStatsUnit);
899 }
900
Georgios Katsikas83600982017-05-28 20:41:45 +0200901 // Time (ns) to parse the controller's deployment instruction
Georgios Katsikasfda66742018-07-31 20:18:14 +0200902 long parsingTime = 0;
903 if (timingObjNode.get(TIMING_PARAM_PARSE) != null) {
904 parsingTime = timingObjNode.path(TIMING_PARAM_PARSE).asLong();
905 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200906 // Time (ns) to do the deployment
Georgios Katsikasfda66742018-07-31 20:18:14 +0200907 long launchingTime = 0;
908 if (timingObjNode.get(TIMING_PARAM_LAUNCH) != null) {
909 launchingTime = timingObjNode.path(TIMING_PARAM_LAUNCH).asLong();
910 }
911 // Deployment time (ns) equals to time to parse + time to launch
912 long deployTime = 0;
913 if (timingObjNode.get(TIMING_PARAM_DEPLOY) != null) {
914 deployTime = timingObjNode.path(TIMING_PARAM_DEPLOY).asLong();
915 }
916 checkArgument(deployTime == parsingTime + launchingTime, "Inconsistent timing statistics");
917
918 timingBuilder.setParsingTime(parsingTime)
919 .setLaunchingTime(launchingTime);
Georgios Katsikas83600982017-05-28 20:41:45 +0200920
921 // Get autoscale timing statistics
922 JsonNode autoscaleTimingNode = objNode.path(PARAM_TIMING_AUTOSCALE);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200923 if (autoscaleTimingNode == null) {
924 return timingBuilder.build();
925 }
926
Georgios Katsikas83600982017-05-28 20:41:45 +0200927 ObjectNode autoscaleTimingObjNode = (ObjectNode) autoscaleTimingNode;
Georgios Katsikas83600982017-05-28 20:41:45 +0200928 // Time (ns) to autoscale a server's load
Georgios Katsikasfda66742018-07-31 20:18:14 +0200929 long autoscaleTime = 0;
930 if (autoscaleTimingObjNode.get(TIMING_PARAM_AUTOSCALE) != null) {
931 autoscaleTimingObjNode.path(TIMING_PARAM_AUTOSCALE).asLong();
932 }
933 timingBuilder.setAutoscaleTime(autoscaleTime);
Georgios Katsikas83600982017-05-28 20:41:45 +0200934
935 return timingBuilder.build();
936 }
937
938 /**
939 * Return a timing statistics object with zero counters.
940 * This is useful when constructing MonitoringStatistics
941 * objects that do not require timers.
942 *
943 * @return TimingStatistics object
944 */
945 private TimingStatistics getZeroTimingStatistics() {
Georgios Katsikasfda66742018-07-31 20:18:14 +0200946 DefaultTimingStatistics.Builder zeroTimingBuilder = DefaultTimingStatistics.builder();
Georgios Katsikas83600982017-05-28 20:41:45 +0200947
948 zeroTimingBuilder.setParsingTime(0)
949 .setLaunchingTime(0)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200950 .setAutoscaleTime(0);
Georgios Katsikas83600982017-05-28 20:41:45 +0200951
952 return zeroTimingBuilder.build();
953 }
954
955}