blob: eedb403218ea871a8af10e56b6425acc9b8765f2 [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";
Georgios Katsikasfda66742018-07-31 20:18:14 +0200153 private static final String MON_PARAM_MAX = "max";
Georgios Katsikas83600982017-05-28 20:41:45 +0200154
155 /**
156 * Timing statistics.
157 */
Georgios Katsikasfda66742018-07-31 20:18:14 +0200158 private static final String TIMING_PARAM_PARSE = "parseTime";
159 private static final String TIMING_PARAM_LAUNCH = "launchTime";
160 private static final String TIMING_PARAM_DEPLOY = "deployTime";
161 private static final String TIMING_PARAM_AUTOSCALE = "autoScaleTime";
Georgios Katsikas83600982017-05-28 20:41:45 +0200162
163 /**
164 * Auxiliary constants.
165 */
166 private static final short DISCOVERY_RETRIES = 3;
167 private static final String CPU_VENDOR_NULL = "Unsupported CPU vendor" +
168 " Choose one in: " + BasicServerDriver.enumTypesToString(CpuVendor.class);
169 private static final String NIC_RX_FILTER_NULL = "Unsupported NIC Rx filter" +
170 " Choose one in: " + BasicServerDriver.enumTypesToString(RxFilter.class);
171
172 /**
173 * Port types that usually appear in commodity servers.
174 */
175 public static final Map<String, Port.Type> PORT_TYPE_MAP =
176 Collections.unmodifiableMap(
177 new HashMap<String, Port.Type>() {
178 {
179 put(NIC_PARAM_PORT_TYPE_FIBER, Port.Type.FIBER);
180 put(NIC_PARAM_PORT_TYPE_COPPER, Port.Type.COPPER);
181 }
182 }
183 );
184
185 /**
186 * Constructs server device discovery.
187 */
188 public ServerDevicesDiscovery() {
189 super();
190 log.debug("Started");
191 }
192
193 @Override
194 public Set<DeviceId> deviceIds() {
195 // Set of devices to return
196 Set<DeviceId> devices = new HashSet<DeviceId>();
197
198 DeviceId deviceId = getHandler().data().deviceId();
199 checkNotNull(deviceId, DEVICE_ID_NULL);
200 devices.add(deviceId);
201
202 return devices;
203 }
204
205 @Override
206 public DeviceDescription deviceDetails(DeviceId deviceId) {
207 return getDeviceDetails(deviceId);
208 }
209
210 @Override
211 public DeviceDescription discoverDeviceDetails() {
212 return getDeviceDetails(null);
213 }
214
215 /**
216 * Query a server to retrieve its features.
217 *
218 * @param deviceId the device ID to be queried
219 * @return a DeviceDescription with the device's features
220 */
221 private DeviceDescription getDeviceDetails(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200222 // Retrieve the device ID, if null given
223 if (deviceId == null) {
224 deviceId = getHandler().data().deviceId();
225 checkNotNull(deviceId, DEVICE_ID_NULL);
226 }
227
228 // Get the device
229 RestSBDevice device = getController().getDevice(deviceId);
230 checkNotNull(device, DEVICE_NULL);
231
232 // Hit the path that provides the server's resources
233 InputStream response = null;
234 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200235 response = getController().get(deviceId, RESOURCE_DISCOVERY_URL, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200236 } catch (ProcessingException pEx) {
237 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200238 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200239 }
240
241 // Load the JSON into objects
242 ObjectMapper mapper = new ObjectMapper();
243 Map<String, Object> jsonMap = null;
244 JsonNode jsonNode = null;
245 ObjectNode objNode = null;
246 try {
247 jsonMap = mapper.readValue(response, Map.class);
248 jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
249 objNode = (ObjectNode) jsonNode;
250 } catch (IOException ioEx) {
251 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200252 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200253 }
254
255 if (jsonMap == null) {
256 log.error("Failed to discover the device details of: {}", deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200257 return null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200258 }
259
260 // Get all the attributes
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200261 String id = get(jsonNode, BasicServerDriver.PARAM_ID);
Georgios Katsikas83600982017-05-28 20:41:45 +0200262 String vendor = get(jsonNode, PARAM_MANUFACTURER);
263 String hw = get(jsonNode, PARAM_HW_VENDOR);
264 String sw = get(jsonNode, PARAM_SW_VENDOR);
265 String serial = get(jsonNode, PARAM_SERIAL);
266
267 // CPUs are composite attributes
268 Set<CpuDevice> cpuSet = new HashSet<CpuDevice>();
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200269 JsonNode cpuNode = objNode.path(BasicServerDriver.PARAM_CPUS);
Georgios Katsikas83600982017-05-28 20:41:45 +0200270
271 // Construct CPU objects
272 for (JsonNode cn : cpuNode) {
273 ObjectNode cpuObjNode = (ObjectNode) cn;
274
275 // All the CPU attributes
276 int cpuId = cpuObjNode.path(CPU_PARAM_ID).asInt();
277 String cpuVendorStr = get(cn, CPU_PARAM_VENDOR);
278 long cpuFrequency = cpuObjNode.path(CPU_PARAM_FREQUENCY).asLong();
279
280 // Verify that this is a valid vendor
281 CpuVendor cpuVendor = CpuVendor.getByName(cpuVendorStr);
282 checkNotNull(cpuVendor, CPU_VENDOR_NULL);
283
284 // Construct a CPU device
285 CpuDevice cpu = new DefaultCpuDevice(cpuId, cpuVendor, cpuFrequency);
286
287 // Add it to the set
288 cpuSet.add(cpu);
289 }
290
291 // NICs are composite attributes too
292 Set<NicDevice> nicSet = new HashSet<NicDevice>();
293 JsonNode nicNode = objNode.path(PARAM_NICS);
294
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200295 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
296
Georgios Katsikas83600982017-05-28 20:41:45 +0200297 // Construct NIC objects
298 for (JsonNode nn : nicNode) {
299 ObjectNode nicObjNode = (ObjectNode) nn;
300
301 // All the NIC attributes
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200302 String nicName = get(nn, NIC_PARAM_NAME);
303 long nicIndex = nicObjNode.path(NIC_PARAM_PORT_INDEX).asLong();
Georgios Katsikas83600982017-05-28 20:41:45 +0200304 long speed = nicObjNode.path(NIC_PARAM_SPEED).asLong();
305 String portTypeStr = get(nn, NIC_PARAM_PORT_TYPE);
306 Port.Type portType = PORT_TYPE_MAP.get(portTypeStr);
307 if (portType == null) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800308 throw new IllegalArgumentException(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200309 portTypeStr + " is not a valid port type for NIC " + nicName);
Georgios Katsikas83600982017-05-28 20:41:45 +0200310 }
311 boolean status = nicObjNode.path(NIC_PARAM_STATUS).asInt() > 0;
312 String hwAddr = get(nn, NIC_PARAM_HW_ADDR);
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200313 JsonNode tagNode = nicObjNode.path(BasicServerDriver.NIC_PARAM_RX_FILTER);
Georgios Katsikas83600982017-05-28 20:41:45 +0200314 if (tagNode == null) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800315 throw new IllegalArgumentException(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200316 "The Rx filters of NIC " + nicName + " are not reported");
Georgios Katsikas83600982017-05-28 20:41:45 +0200317 }
318
319 // Convert the JSON list into an array of strings
320 List<String> rxFilters = null;
321 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200322 rxFilters = mapper.readValue(tagNode.traverse(),
323 new TypeReference<ArrayList<String>>() { });
Georgios Katsikas83600982017-05-28 20:41:45 +0200324 } catch (IOException ioEx) {
325 continue;
326 }
327
328 // Parse the array of strings and create an RxFilter object
329 NicRxFilter rxFilterMechanism = new NicRxFilter();
330 for (String s : rxFilters) {
331 // Verify that this is a valid Rx filter
332 RxFilter rf = RxFilter.getByName(s);
333 checkNotNull(rf, NIC_RX_FILTER_NULL);
334
335 rxFilterMechanism.addRxFilter(rf);
336 }
337
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200338 // Store NIC name to number mapping as an annotation
339 annotations.set(nicName, Long.toString(nicIndex));
340
Georgios Katsikas83600982017-05-28 20:41:45 +0200341 // Construct a NIC device for this server
342 NicDevice nic = new DefaultNicDevice(
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200343 nicName, nicIndex, portType, speed, status, hwAddr, rxFilterMechanism);
Georgios Katsikas83600982017-05-28 20:41:45 +0200344
345 // Add it to the set
346 nicSet.add(nic);
347 }
348
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200349 // Construct a complete server device object.
350 // Lists of NICs and CPUs extend the information
351 // already in RestSBDevice (parent class).
Georgios Katsikas83600982017-05-28 20:41:45 +0200352 RestServerSBDevice dev = new DefaultRestServerSBDevice(
353 device.ip(), device.port(), device.username(),
354 device.password(), device.protocol(), device.url(),
Georgios Katsikasdb148472018-10-27 20:48:13 +0200355 device.isActive(), device.testUrl().orElse(""),
Georgios Katsikas83600982017-05-28 20:41:45 +0200356 vendor, hw, sw, AuthenticationScheme.BASIC, "",
357 cpuSet, nicSet
358 );
359 checkNotNull(dev, DEVICE_NULL);
360
Georgios Katsikasfda66742018-07-31 20:18:14 +0200361 // Set alive
362 raiseDeviceReconnect(dev);
363
Georgios Katsikas83600982017-05-28 20:41:45 +0200364 // Updates the controller with the complete device information
365 getController().removeDevice(deviceId);
366 getController().addDevice((RestSBDevice) dev);
367
Georgios Katsikas30bede52018-07-28 14:46:07 +0200368 // Create a description for this server device
369 ServerDeviceDescription desc = null;
370
Georgios Katsikas83600982017-05-28 20:41:45 +0200371 try {
372 desc = new DefaultServerDeviceDescription(
Georgios Katsikas40ecef32018-07-03 11:17:44 +0200373 new URI(id), Device.Type.SERVER, vendor,
Georgios Katsikas83600982017-05-28 20:41:45 +0200374 hw, sw, serial, new ChassisId(),
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200375 cpuSet, nicSet, annotations.build()
Georgios Katsikas83600982017-05-28 20:41:45 +0200376 );
377 } catch (URISyntaxException uEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200378 log.error("Failed to create a server device description for: {}",
379 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200380 return null;
381 }
382
383 log.info("Device's {} details sent to the controller", deviceId);
384
385 return desc;
386 }
387
388 @Override
389 public List<PortDescription> discoverPortDetails() {
Georgios Katsikas83600982017-05-28 20:41:45 +0200390 // Retrieve the device ID
391 DeviceId deviceId = getHandler().data().deviceId();
392 checkNotNull(deviceId, DEVICE_ID_NULL);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200393
Georgios Katsikas83600982017-05-28 20:41:45 +0200394 // .. and object
395 RestServerSBDevice device = null;
Georgios Katsikas30bede52018-07-28 14:46:07 +0200396 try {
397 device = (RestServerSBDevice) getController().getDevice(deviceId);
398 } catch (ClassCastException ccEx) {
399 log.error("Failed to discover ports for device {}", deviceId);
400 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200401 }
402
Georgios Katsikas30bede52018-07-28 14:46:07 +0200403 if (device == null) {
404 log.error("No device with ID {} is available for port discovery", deviceId);
405 return Collections.EMPTY_LIST;
406 }
407 if ((device.nics() == null) || (device.nics().size() == 0)) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200408 log.error("No ports available on {}", deviceId);
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200409 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200410 }
411
Georgios Katsikas30bede52018-07-28 14:46:07 +0200412 // List of port descriptions to return
413 List<PortDescription> portDescriptions = Lists.newArrayList();
414
Georgios Katsikas83600982017-05-28 20:41:45 +0200415 // Sorted list of NIC ports
416 Set<NicDevice> nics = new TreeSet(device.nics());
417
418 // Iterate through the NICs of this device to populate the list
Georgios Katsikas83600982017-05-28 20:41:45 +0200419 for (NicDevice nic : nics) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200420 // Include the name of this device as an annotation
421 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200422 .set(AnnotationKeys.PORT_NAME, nic.name());
Georgios Katsikas83600982017-05-28 20:41:45 +0200423
424 // Create a port description and add it to the list
425 portDescriptions.add(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800426 DefaultPortDescription.builder()
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200427 .withPortNumber(PortNumber.portNumber(nic.portNumber(), nic.name()))
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800428 .isEnabled(nic.status())
429 .type(nic.portType())
430 .portSpeed(nic.speed())
431 .annotations(annotations.build())
432 .build());
Georgios Katsikas83600982017-05-28 20:41:45 +0200433
Georgios Katsikasd472a322018-07-08 19:58:25 +0200434 log.info("Port discovery on device {}: NIC {} is {} at {} Mbps",
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200435 deviceId, nic.portNumber(), nic.status() ? "up" : "down",
Georgios Katsikasd472a322018-07-08 19:58:25 +0200436 nic.speed());
Georgios Katsikas83600982017-05-28 20:41:45 +0200437 }
438
439 return ImmutableList.copyOf(portDescriptions);
440 }
441
442 @Override
443 public Collection<PortStatistics> discoverPortStatistics() {
444 // Retrieve the device ID
445 DeviceId deviceId = getHandler().data().deviceId();
446 checkNotNull(deviceId, DEVICE_ID_NULL);
447
448 // Get port statistics for this device
449 return getPortStatistics(deviceId);
450 }
451
452 /**
453 * Query a server to retrieve its port statistics.
454 *
455 * @param deviceId the device ID to be queried
456 * @return list of (per port) PortStatistics
457 */
458 private Collection<PortStatistics> getPortStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200459 // Get global monitoring statistics
460 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
461 if (monStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200462 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200463 }
464
465 // Filter out the NIC statistics
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200466 Collection<PortStatistics> portStats = monStats.nicStatisticsAll();
Georgios Katsikas83600982017-05-28 20:41:45 +0200467 if (portStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200468 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200469 }
470
471 log.debug("Port statistics: {}", portStats.toString());
472
473 return portStats;
474 }
475
476 @Override
477 public Collection<CpuStatistics> discoverCpuStatistics() {
478 // Retrieve the device ID
479 DeviceId deviceId = getHandler().data().deviceId();
480 checkNotNull(deviceId, DEVICE_ID_NULL);
481
482 // Get CPU statistics for this device
483 return getCpuStatistics(deviceId);
484 }
485
486 /**
487 * Query a server to retrieve its CPU statistics.
488 *
489 * @param deviceId the device ID to be queried
490 * @return list of (per core) CpuStatistics
491 */
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200492 public Collection<CpuStatistics> getCpuStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200493 // Get global monitoring statistics
494 MonitoringStatistics monStats = getGlobalMonitoringStatistics(deviceId);
495 if (monStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200496 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200497 }
498
499 // Filter out the CPU statistics
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200500 Collection<CpuStatistics> cpuStats = monStats.cpuStatisticsAll();
Georgios Katsikas83600982017-05-28 20:41:45 +0200501 if (cpuStats == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200502 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200503 }
504
505 log.debug("CPU statistics: {}", cpuStats.toString());
506
507 return cpuStats;
508 }
509
510 @Override
511 public MonitoringStatistics discoverGlobalMonitoringStatistics() {
512 // Retrieve the device ID
513 DeviceId deviceId = getHandler().data().deviceId();
514 checkNotNull(deviceId, DEVICE_ID_NULL);
515
516 // Get global monitoring statistics for this device
517 return getGlobalMonitoringStatistics(deviceId);
518 }
519
520 /**
521 * Query a server to retrieve its global monitoring statistics.
522 *
523 * @param deviceId the device ID to be queried
524 * @return global monitoring statistics
525 */
Georgios Katsikasfda66742018-07-31 20:18:14 +0200526 public MonitoringStatistics getGlobalMonitoringStatistics(DeviceId deviceId) {
Georgios Katsikas83600982017-05-28 20:41:45 +0200527 // Monitoring statistics to return
528 MonitoringStatistics monStats = null;
529
530 RestServerSBDevice device = null;
531 try {
532 device = (RestServerSBDevice) getController().getDevice(deviceId);
533 } catch (ClassCastException ccEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200534 log.error("Failed to retrieve global monitoring statistics from device {}",
535 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200536 return monStats;
537 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200538 if ((device == null) || (!device.isActive())) {
539 return monStats;
540 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200541
542 // Hit the path that provides the server's global resources
543 InputStream response = null;
544 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200545 response = getController().get(deviceId, GLOBAL_STATS_URL, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200546 } catch (ProcessingException pEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200547 log.error("Failed to retrieve global monitoring statistics from device {}",
548 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200549 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200550 return monStats;
551 }
552
553 // Load the JSON into objects
554 ObjectMapper mapper = new ObjectMapper();
555 Map<String, Object> jsonMap = null;
Georgios Katsikas83600982017-05-28 20:41:45 +0200556 ObjectNode objNode = null;
557 try {
558 jsonMap = mapper.readValue(response, Map.class);
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200559 JsonNode jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
Georgios Katsikas83600982017-05-28 20:41:45 +0200560 objNode = (ObjectNode) jsonNode;
561 } catch (IOException ioEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200562 log.error("Failed to retrieve global monitoring statistics from device {}",
563 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200564 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200565 return monStats;
566 }
567
568 if (jsonMap == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200569 log.error("Failed to retrieve global monitoring statistics from device {}",
570 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200571 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200572 return monStats;
573 }
574
575 // Get high-level CPU statistics
Georgios Katsikasfda66742018-07-31 20:18:14 +0200576 int busyCpus = objNode.path(MON_PARAM_BUSY_CPUS).asInt();
577 int freeCpus = objNode.path(MON_PARAM_FREE_CPUS).asInt();
Georgios Katsikas83600982017-05-28 20:41:45 +0200578
579 // Get a list of CPU statistics per core
580 Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode);
581
582 // Get a list of port statistics
583 Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode);
584
585 // Get zero timing statistics
586 TimingStatistics timinsgStats = getZeroTimingStatistics();
587
588 // Ready to construct the grand object
589 DefaultMonitoringStatistics.Builder statsBuilder =
590 DefaultMonitoringStatistics.builder();
591
592 statsBuilder.setDeviceId(deviceId)
593 .setTimingStatistics(timinsgStats)
594 .setCpuStatistics(cpuStats)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200595 .setNicStatistics(nicStats);
Georgios Katsikas83600982017-05-28 20:41:45 +0200596
597 monStats = statsBuilder.build();
598
Georgios Katsikasfda66742018-07-31 20:18:14 +0200599 // When a device reports monitoring data, it means it is alive
600 raiseDeviceReconnect(device);
601
Georgios Katsikas83600982017-05-28 20:41:45 +0200602 log.debug("Global monitoring statistics: {}", monStats.toString());
603
604 return monStats;
605 }
606
607 @Override
608 public MonitoringStatistics discoverMonitoringStatistics(URI tcId) {
609 // Retrieve the device ID
610 DeviceId deviceId = getHandler().data().deviceId();
611 checkNotNull(deviceId, DEVICE_ID_NULL);
612
613 // Get resource-specific monitoring statistics for this device
614 return getMonitoringStatistics(deviceId, tcId);
615 }
616
617 /**
618 * Query a server to retrieve monitoring statistics for a
619 * specific resource (i.e., traffic class).
620 *
621 * @param deviceId the device ID to be queried
622 * @param tcId the ID of the traffic class to be monitored
623 * @return resource-specific monitoring statistics
624 */
625 private MonitoringStatistics getMonitoringStatistics(DeviceId deviceId, URI tcId) {
626 // Monitoring statistics to return
627 MonitoringStatistics monStats = null;
628
629 RestServerSBDevice device = null;
630 try {
631 device = (RestServerSBDevice) getController().getDevice(deviceId);
632 } catch (ClassCastException ccEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200633 log.error("Failed to retrieve monitoring statistics from device {}",
634 deviceId);
Georgios Katsikas83600982017-05-28 20:41:45 +0200635 return monStats;
636 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200637 if (device == null) {
638 return monStats;
639 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200640
641 // Create a resource-specific URL
Georgios Katsikas30bede52018-07-28 14:46:07 +0200642 String scUrl = SERVICE_CHAINS_STATS_URL + SLASH + tcId.toString();
Georgios Katsikas83600982017-05-28 20:41:45 +0200643
644 // Hit the path that provides the server's specific resources
645 InputStream response = null;
646 try {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200647 response = getController().get(deviceId, scUrl, JSON);
Georgios Katsikas83600982017-05-28 20:41:45 +0200648 } catch (ProcessingException pEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200649 log.error("Failed to retrieve monitoring statistics from device {}",
650 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200651 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200652 return monStats;
653 }
654
655 // Load the JSON into objects
656 ObjectMapper mapper = new ObjectMapper();
657 Map<String, Object> jsonMap = null;
658 JsonNode jsonNode = null;
659 ObjectNode objNode = null;
660 try {
661 jsonMap = mapper.readValue(response, Map.class);
662 jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
663 objNode = (ObjectNode) jsonNode;
664 } catch (IOException ioEx) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200665 log.error("Failed to retrieve monitoring statistics from device {}",
666 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200667 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200668 return monStats;
669 }
670
671 if (jsonMap == null) {
Georgios Katsikasd472a322018-07-08 19:58:25 +0200672 log.error("Failed to retrieve monitoring statistics from device {}",
673 deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200674 raiseDeviceDisconnect(device);
Georgios Katsikas83600982017-05-28 20:41:45 +0200675 return monStats;
676 }
677
678 // Get the ID of the traffic class
679 String id = get(jsonNode, PARAM_ID);
680
681 // And verify that this is the traffic class we want to monitor
682 if (!id.equals(tcId.toString())) {
Ray Milkey067c44b2018-02-26 12:48:23 -0800683 throw new IllegalStateException(
Georgios Katsikas83600982017-05-28 20:41:45 +0200684 "Failed to retrieve monitoring data for traffic class " + tcId +
685 ". Traffic class ID does not agree."
686 );
687 }
688
689 // Get a list of CPU statistics per core
690 Collection<CpuStatistics> cpuStats = parseCpuStatistics(deviceId, objNode);
691
692 // Get a list of port statistics
693 Collection<PortStatistics> nicStats = parseNicStatistics(deviceId, objNode);
694
695 // Get timing statistics
696 TimingStatistics timinsgStats = parseTimingStatistics(objNode);
697
698 // Ready to construct the grand object
699 DefaultMonitoringStatistics.Builder statsBuilder =
700 DefaultMonitoringStatistics.builder();
701
702 statsBuilder.setDeviceId(deviceId)
703 .setTimingStatistics(timinsgStats)
704 .setCpuStatistics(cpuStats)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200705 .setNicStatistics(nicStats);
Georgios Katsikas83600982017-05-28 20:41:45 +0200706
707 monStats = statsBuilder.build();
708
Georgios Katsikasfda66742018-07-31 20:18:14 +0200709 // When a device reports monitoring data, it means it is alive
710 raiseDeviceReconnect(device);
711
Georgios Katsikas83600982017-05-28 20:41:45 +0200712 log.debug("Monitoring statistics: {}", monStats.toString());
713
714 return monStats;
715 }
716
717 /**
718 * Parse the input JSON object, looking for CPU-related
719 * statistics. Upon success, construct and return a list
720 * of CPU statistics objects.
721 *
722 * @param deviceId the device ID that sent the JSON object
723 * @param objNode input JSON node with CPU statistics information
724 * @return list of (per core) CpuStatistics
725 */
Georgios Katsikas30bede52018-07-28 14:46:07 +0200726 private Collection<CpuStatistics> parseCpuStatistics(DeviceId deviceId, JsonNode objNode) {
727 if ((deviceId == null) || (objNode == null)) {
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200728 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200729 }
730
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200731 Collection<CpuStatistics> cpuStats = Lists.newArrayList();
732
Georgios Katsikas2ebd8a02018-06-27 18:32:50 +0200733 JsonNode cpuNode = objNode.path(BasicServerDriver.PARAM_CPUS);
Georgios Katsikas83600982017-05-28 20:41:45 +0200734
735 for (JsonNode cn : cpuNode) {
736 ObjectNode cpuObjNode = (ObjectNode) cn;
737
Georgios Katsikasfda66742018-07-31 20:18:14 +0200738 // CPU statistics builder
739 DefaultCpuStatistics.Builder cpuBuilder = DefaultCpuStatistics.builder();
740
741 // Throughput statistics are optional
742 JsonNode throughputNode = cpuObjNode.get(CPU_PARAM_THROUGHPUT);
743 if (throughputNode != null) {
744 String throughputUnit = get(throughputNode, MON_PARAM_UNIT);
745 if (!Strings.isNullOrEmpty(throughputUnit)) {
746 cpuBuilder.setThroughputUnit(throughputUnit);
747 }
748 float averageThroughput = (float) 0;
749 if (throughputNode.get(MON_PARAM_AVERAGE) != null) {
750 averageThroughput = throughputNode.path(MON_PARAM_AVERAGE).floatValue();
751 }
752 cpuBuilder.setAverageThroughput(averageThroughput);
753 }
754
755 // Latency statistics are optional
756 JsonNode latencyNode = cpuObjNode.get(CPU_PARAM_LATENCY);
757 if (latencyNode != null) {
758 String latencyUnit = get(latencyNode, MON_PARAM_UNIT);
759 if (!Strings.isNullOrEmpty(latencyUnit)) {
760 cpuBuilder.setLatencyUnit(latencyUnit);
761 }
762 float minLatency = (float) 0;
763 if (latencyNode.get(MON_PARAM_MIN) != null) {
764 minLatency = latencyNode.path(MON_PARAM_MIN).floatValue();
765 }
Georgios Katsikas973a2652018-06-28 08:45:47 +0200766 float averageLatency = (float) 0;
767 if (latencyNode.get(MON_PARAM_AVERAGE) != null) {
768 averageLatency = latencyNode.path(MON_PARAM_AVERAGE).floatValue();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200769 }
770 float maxLatency = (float) 0;
771 if (latencyNode.get(MON_PARAM_MAX) != null) {
772 maxLatency = latencyNode.path(MON_PARAM_MAX).floatValue();
773 }
774
775 cpuBuilder.setMinLatency(minLatency)
Georgios Katsikas973a2652018-06-28 08:45:47 +0200776 .setAverageLatency(averageLatency)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200777 .setMaxLatency(maxLatency);
778 }
779
Georgios Katsikas83600982017-05-28 20:41:45 +0200780 // CPU ID with its load and status
Georgios Katsikasfda66742018-07-31 20:18:14 +0200781 int cpuId = cpuObjNode.path(CPU_PARAM_ID).asInt();
782 float cpuLoad = cpuObjNode.path(CPU_PARAM_LOAD).floatValue();
783 int queueId = cpuObjNode.path(CPU_PARAM_QUEUE).asInt();
Georgios Katsikas6dc11c12018-12-20 08:43:29 +0100784 int busySince = cpuObjNode.path(CPU_PARAM_STATUS).asInt();
Georgios Katsikas83600982017-05-28 20:41:45 +0200785
Georgios Katsikasfda66742018-07-31 20:18:14 +0200786 // This is mandatory information
Georgios Katsikas83600982017-05-28 20:41:45 +0200787 cpuBuilder.setDeviceId(deviceId)
788 .setId(cpuId)
789 .setLoad(cpuLoad)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200790 .setQueue(queueId)
Georgios Katsikas6dc11c12018-12-20 08:43:29 +0100791 .setBusySince(busySince);
Georgios Katsikas83600982017-05-28 20:41:45 +0200792
Georgios Katsikasfda66742018-07-31 20:18:14 +0200793 // We have all the statistics for this CPU core
Georgios Katsikas83600982017-05-28 20:41:45 +0200794 cpuStats.add(cpuBuilder.build());
795 }
796
797 return cpuStats;
798 }
799
800 /**
801 * Parse the input JSON object, looking for NIC-related
802 * statistics. Upon success, construct and return a list
803 * of NIC statistics objects.
804 *
805 * @param deviceId the device ID that sent the JSON object
806 * @param objNode input JSON node with NIC statistics information
807 * @return list of (per port) PortStatistics
808 */
Georgios Katsikas30bede52018-07-28 14:46:07 +0200809 private Collection<PortStatistics> parseNicStatistics(DeviceId deviceId, JsonNode objNode) {
810 if ((deviceId == null) || (objNode == null)) {
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200811 return Collections.EMPTY_LIST;
Georgios Katsikas83600982017-05-28 20:41:45 +0200812 }
813
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200814 RestServerSBDevice device = null;
815 try {
816 device = (RestServerSBDevice) getController().getDevice(deviceId);
817 } catch (ClassCastException ccEx) {
818 return Collections.EMPTY_LIST;
819 }
Georgios Katsikas30bede52018-07-28 14:46:07 +0200820 if (device == null) {
821 return Collections.EMPTY_LIST;
822 }
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200823
824 Collection<PortStatistics> nicStats = Lists.newArrayList();
825
Georgios Katsikas83600982017-05-28 20:41:45 +0200826 JsonNode nicNode = objNode.path(PARAM_NICS);
827
828 for (JsonNode nn : nicNode) {
829 ObjectNode nicObjNode = (ObjectNode) nn;
830
831 // All the NIC attributes
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200832 String nicName = get(nn, NIC_PARAM_NAME);
833 checkArgument(!Strings.isNullOrEmpty(nicName), "NIC name is empty or NULL");
834
835 long portNumber = device.portNumberFromName(nicName);
836 checkArgument(portNumber >= 0, "Unknown port ID " + portNumber + " for NIC " + nicName);
Georgios Katsikas83600982017-05-28 20:41:45 +0200837
838 long rxCount = nicObjNode.path(NIC_STATS_RX_COUNT).asLong();
839 long rxBytes = nicObjNode.path(NIC_STATS_RX_BYTES).asLong();
840 long rxDropped = nicObjNode.path(NIC_STATS_RX_DROPS).asLong();
841 long rxErrors = nicObjNode.path(NIC_STATS_RX_ERRORS).asLong();
842 long txCount = nicObjNode.path(NIC_STATS_TX_COUNT).asLong();
843 long txBytes = nicObjNode.path(NIC_STATS_TX_BYTES).asLong();
844 long txDropped = nicObjNode.path(NIC_STATS_TX_DROPS).asLong();
845 long txErrors = nicObjNode.path(NIC_STATS_TX_ERRORS).asLong();
846
847 // Incorporate these statistics into an object
Georgios Katsikasfda66742018-07-31 20:18:14 +0200848 DefaultPortStatistics.Builder nicBuilder = DefaultPortStatistics.builder();
Georgios Katsikas83600982017-05-28 20:41:45 +0200849
850 nicBuilder.setDeviceId(deviceId)
Ray Milkey5ec42082019-02-13 09:56:07 -0800851 .setPort(PortNumber.portNumber(portNumber))
Georgios Katsikas83600982017-05-28 20:41:45 +0200852 .setPacketsReceived(rxCount)
853 .setPacketsSent(txCount)
854 .setBytesReceived(rxBytes)
855 .setBytesSent(txBytes)
856 .setPacketsRxDropped(rxDropped)
857 .setPacketsRxErrors(rxErrors)
858 .setPacketsTxDropped(txDropped)
Georgios Katsikasfda66742018-07-31 20:18:14 +0200859 .setPacketsTxErrors(txErrors);
Georgios Katsikas83600982017-05-28 20:41:45 +0200860
861 // We have statistics for this NIC
862 nicStats.add(nicBuilder.build());
863 }
864
865 return nicStats;
866 }
867
868 /**
Georgios Katsikasfda66742018-07-31 20:18:14 +0200869 * Parse the input JSON object, looking for timing-related statistics.
870 * Upon success, return a timing statistics object with the advertized values.
871 * Upon failure, return a timing statistics object with zero-initialized values.
Georgios Katsikas83600982017-05-28 20:41:45 +0200872 *
873 * @param objNode input JSON node with timing statistics information
874 * @return TimingStatistics object or null
875 */
876 private TimingStatistics parseTimingStatistics(JsonNode objNode) {
877 TimingStatistics timinsgStats = null;
878
879 if (objNode == null) {
880 return timinsgStats;
881 }
882
Georgios Katsikasfda66742018-07-31 20:18:14 +0200883 // If no timing statistics are present, then send zeros
884 if (objNode.get(PARAM_TIMING_STATS) == null) {
885 return getZeroTimingStatistics();
886 }
887
888 DefaultTimingStatistics.Builder timingBuilder = DefaultTimingStatistics.builder();
889
Georgios Katsikas83600982017-05-28 20:41:45 +0200890 // Get timing statistics
891 JsonNode timingNode = objNode.path(PARAM_TIMING_STATS);
892 ObjectNode timingObjNode = (ObjectNode) timingNode;
893
Georgios Katsikasfda66742018-07-31 20:18:14 +0200894 // The unit of timing statistics
895 String timingStatsUnit = get(timingNode, MON_PARAM_UNIT);
896 if (!Strings.isNullOrEmpty(timingStatsUnit)) {
897 timingBuilder.setUnit(timingStatsUnit);
898 }
899
Georgios Katsikas83600982017-05-28 20:41:45 +0200900 // Time (ns) to parse the controller's deployment instruction
Georgios Katsikasfda66742018-07-31 20:18:14 +0200901 long parsingTime = 0;
902 if (timingObjNode.get(TIMING_PARAM_PARSE) != null) {
903 parsingTime = timingObjNode.path(TIMING_PARAM_PARSE).asLong();
904 }
Georgios Katsikas83600982017-05-28 20:41:45 +0200905 // Time (ns) to do the deployment
Georgios Katsikasfda66742018-07-31 20:18:14 +0200906 long launchingTime = 0;
907 if (timingObjNode.get(TIMING_PARAM_LAUNCH) != null) {
908 launchingTime = timingObjNode.path(TIMING_PARAM_LAUNCH).asLong();
909 }
910 // Deployment time (ns) equals to time to parse + time to launch
911 long deployTime = 0;
912 if (timingObjNode.get(TIMING_PARAM_DEPLOY) != null) {
913 deployTime = timingObjNode.path(TIMING_PARAM_DEPLOY).asLong();
914 }
915 checkArgument(deployTime == parsingTime + launchingTime, "Inconsistent timing statistics");
916
917 timingBuilder.setParsingTime(parsingTime)
918 .setLaunchingTime(launchingTime);
Georgios Katsikas83600982017-05-28 20:41:45 +0200919
920 // Get autoscale timing statistics
921 JsonNode autoscaleTimingNode = objNode.path(PARAM_TIMING_AUTOSCALE);
Georgios Katsikasfda66742018-07-31 20:18:14 +0200922 if (autoscaleTimingNode == null) {
923 return timingBuilder.build();
924 }
925
Georgios Katsikas973a2652018-06-28 08:45:47 +0200926 ObjectNode autoScaleTimingObjNode = (ObjectNode) autoscaleTimingNode;
Georgios Katsikas83600982017-05-28 20:41:45 +0200927 // Time (ns) to autoscale a server's load
Georgios Katsikas973a2652018-06-28 08:45:47 +0200928 long autoScaleTime = 0;
929 if (autoScaleTimingObjNode.get(TIMING_PARAM_AUTOSCALE) != null) {
930 autoScaleTime = autoScaleTimingObjNode.path(TIMING_PARAM_AUTOSCALE).asLong();
Georgios Katsikasfda66742018-07-31 20:18:14 +0200931 }
Georgios Katsikas973a2652018-06-28 08:45:47 +0200932 timingBuilder.setAutoScaleTime(autoScaleTime);
Georgios Katsikas83600982017-05-28 20:41:45 +0200933
934 return timingBuilder.build();
935 }
936
937 /**
938 * Return a timing statistics object with zero counters.
939 * This is useful when constructing MonitoringStatistics
940 * objects that do not require timers.
941 *
942 * @return TimingStatistics object
943 */
944 private TimingStatistics getZeroTimingStatistics() {
Georgios Katsikasfda66742018-07-31 20:18:14 +0200945 DefaultTimingStatistics.Builder zeroTimingBuilder = DefaultTimingStatistics.builder();
Georgios Katsikas83600982017-05-28 20:41:45 +0200946
947 zeroTimingBuilder.setParsingTime(0)
948 .setLaunchingTime(0)
Georgios Katsikas973a2652018-06-28 08:45:47 +0200949 .setAutoScaleTime(0);
Georgios Katsikas83600982017-05-28 20:41:45 +0200950
951 return zeroTimingBuilder.build();
952 }
953
954}