Fix portstats cli for json output.
Jira Id: ONOS-8134
Change-Id: If0f33d1eee230f6ceebf57acebfc81aef599e03c
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
index 8105bff..624be19 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
@@ -15,19 +15,17 @@
*/
package org.onosproject.cli.net;
-import static org.onosproject.cli.net.DevicesListCommand.getSortedDevices;
-import static org.onosproject.net.DeviceId.deviceId;
-
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
@@ -35,6 +33,13 @@
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.PortStatistics;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.onosproject.cli.net.DevicesListCommand.getSortedDevices;
+import static org.onosproject.net.DeviceId.deviceId;
+
/**
* Lists port statistic of all ports in the system.
*/
@@ -49,7 +54,7 @@
@Option(name = "-d", aliases = "--delta",
description = "Show delta port statistics,"
- + "only for the last polling interval",
+ + "only for the last polling interval",
required = false, multiValued = false)
private boolean delta = false;
@@ -83,21 +88,36 @@
}
if (uri == null) {
- for (Device d : getSortedDevices(deviceService)) {
+ if (outputJson()) {
if (delta) {
- if (table) {
- printPortStatsDeltaTable(d.id(), deviceService.getPortDeltaStatistics(d.id()));
- } else {
- printPortStatsDelta(d.id(), deviceService.getPortDeltaStatistics(d.id()));
- }
+ print("%s", jsonPortStatsDelta(deviceService, getSortedDevices(deviceService)));
} else {
- printPortStats(d.id(), deviceService.getPortStatistics(d.id()));
+ print("%s", jsonPortStats(deviceService, getSortedDevices(deviceService)));
+ }
+ } else {
+ for (Device d : getSortedDevices(deviceService)) {
+ if (delta) {
+ if (table) {
+ printPortStatsDeltaTable(d.id(), deviceService.getPortDeltaStatistics(d.id()));
+ } else {
+ printPortStatsDelta(d.id(), deviceService.getPortDeltaStatistics(d.id()));
+ }
+ } else {
+ printPortStats(d.id(), deviceService.getPortStatistics(d.id()));
+ }
}
}
} else {
Device d = deviceService.getDevice(deviceId(uri));
if (d == null) {
error("No such device %s", uri);
+ } else if (outputJson()) {
+ if (delta) {
+ print("%s", jsonPortStatsDelta(d.id(), new ObjectMapper(),
+ deviceService.getPortDeltaStatistics(d.id())));
+ } else {
+ print("%s", jsonPortStats(d.id(), new ObjectMapper(), deviceService.getPortStatistics(d.id())));
+ }
} else if (delta) {
if (table) {
printPortStatsDeltaTable(d.id(), deviceService.getPortDeltaStatistics(d.id()));
@@ -111,6 +131,123 @@
}
/**
+ * Produces JSON array containing portstats of the specified devices.
+ *
+ * @param deviceService device service
+ * @param devices collection of devices
+ * @return JSON Array
+ */
+ protected JsonNode jsonPortStats(DeviceService deviceService, Iterable<Device> devices) {
+ ObjectMapper mapper = new ObjectMapper();
+ ArrayNode result = mapper.createArrayNode();
+
+ for (Device device : devices) {
+ result.add(jsonPortStats(device.id(), mapper, deviceService.getPortStatistics(device.id())));
+ }
+
+ return result;
+ }
+
+ /**
+ * Produces JSON array containing portstats of the specified device.
+ *
+ * @param deviceId device id
+ * @param portStats collection of port statistics
+ * @return JSON array
+ */
+ private JsonNode jsonPortStats(DeviceId deviceId, ObjectMapper mapper, Iterable<PortStatistics> portStats) {
+ ObjectNode result = mapper.createObjectNode();
+ ArrayNode portStatsNode = mapper.createArrayNode();
+
+ for (PortStatistics stat : sortByPort(portStats)) {
+ if (isIrrelevant(stat)) {
+ continue;
+ }
+ if (nonzero && stat.isZero()) {
+ continue;
+ }
+
+ portStatsNode.add(mapper.createObjectNode()
+ .put("port", stat.portNumber().toString())
+ .put("pktRx", stat.packetsReceived())
+ .put("pktTx", stat.packetsSent())
+ .put("bytesRx", stat.bytesReceived())
+ .put("bytesTx", stat.bytesSent())
+ .put("pktRxDrp", stat.packetsRxDropped())
+ .put("pktTxDrp", stat.packetsTxDropped())
+ .put("Dur", stat.durationSec())
+ .set("annotations", annotations(mapper, stat.annotations())));
+ }
+
+ result.put("deviceId", deviceId.toString());
+ result.set("portStats", portStatsNode);
+
+ return result;
+ }
+
+ /**
+ * Produces JSON array containing delta portstats of the specified devices.
+ *
+ * @param deviceService device service
+ * @param devices collection of devices
+ * @return JSON Array
+ */
+ protected JsonNode jsonPortStatsDelta(DeviceService deviceService, Iterable<Device> devices) {
+ ObjectMapper mapper = new ObjectMapper();
+ ArrayNode result = mapper.createArrayNode();
+
+ for (Device device : devices) {
+ result.add(jsonPortStatsDelta(device.id(), mapper, deviceService.getPortDeltaStatistics(device.id())));
+ }
+
+ return result;
+ }
+
+ /**
+ * Produces JSON array containing delta portstats of the specified device id.
+ *
+ * @param deviceId device id
+ * @param portStats collection of port statistics
+ * @return JSON array
+ */
+ private JsonNode jsonPortStatsDelta(DeviceId deviceId, ObjectMapper mapper, Iterable<PortStatistics> portStats) {
+ ObjectNode result = mapper.createObjectNode();
+ ArrayNode portStatsNode = mapper.createArrayNode();
+
+ for (PortStatistics stat : sortByPort(portStats)) {
+ if (isIrrelevant(stat)) {
+ continue;
+ }
+ if (nonzero && stat.isZero()) {
+ continue;
+ }
+
+ float duration = ((float) stat.durationSec()) +
+ (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
+ float rateRx = stat.bytesReceived() * 8 / duration;
+ float rateTx = stat.bytesSent() * 8 / duration;
+
+ portStatsNode.add(mapper.createObjectNode()
+ .put("port", stat.portNumber().toString())
+ .put("pktRx", stat.packetsReceived())
+ .put("pktTx", stat.packetsSent())
+ .put("bytesRx", stat.bytesReceived())
+ .put("bytesTx", stat.bytesSent())
+ .put("rateRx", String.format("%.1f", rateRx))
+ .put("rateTx", String.format("%.1f", rateTx))
+ .put("pktRxDrp", stat.packetsRxDropped())
+ .put("pktTxDrp", stat.packetsTxDropped())
+ .put("interval", String.format("%.3f", duration)));
+ }
+
+ result.put("deviceId", deviceId.toString());
+ result.set("portStats", portStatsNode);
+
+ return result;
+ }
+
+
+ /**
* Prints Port Statistics.
*
* @param deviceId
@@ -197,15 +334,15 @@
float rateRx = duration > 0 ? stat.bytesReceived() * 8 / duration : 0;
float rateTx = duration > 0 ? stat.bytesSent() * 8 / duration : 0;
print(formatDeltaTable, stat.portNumber(),
- humanReadable(stat.packetsReceived()),
- humanReadable(stat.bytesReceived()),
- humanReadableBps(rateRx),
- humanReadable(stat.packetsRxDropped()),
- humanReadable(stat.packetsSent()),
- humanReadable(stat.bytesSent()),
- humanReadableBps(rateTx),
- humanReadable(stat.packetsTxDropped()),
- String.format("%.3f", duration));
+ humanReadable(stat.packetsReceived()),
+ humanReadable(stat.bytesReceived()),
+ humanReadableBps(rateRx),
+ humanReadable(stat.packetsRxDropped()),
+ humanReadable(stat.packetsSent()),
+ humanReadable(stat.bytesSent()),
+ humanReadableBps(rateTx),
+ humanReadable(stat.packetsTxDropped()),
+ String.format("%.3f", duration));
}
print("+---------------------------------------------------------------------------------------------------+");
}
diff --git a/cli/src/test/java/org/onosproject/cli/net/DevicePortStatsCommandTest.java b/cli/src/test/java/org/onosproject/cli/net/DevicePortStatsCommandTest.java
new file mode 100644
index 0000000..7717692
--- /dev/null
+++ b/cli/src/test/java/org/onosproject/cli/net/DevicePortStatsCommandTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.cli.net;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.ChassisId;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DefaultPortStatistics;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortStatistics;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.easymock.EasyMock.*;
+
+/**
+ * Unit test for DevicePortStatsCommand.
+ */
+public class DevicePortStatsCommandTest {
+
+ private DevicePortStatsCommand devicePortStatsCommand;
+ private PortStatistics portStatistics;
+ private DeviceService deviceService;
+ private List<Device> devices = new ArrayList<>();
+ private List<PortStatistics> portStatisticsList = new ArrayList<>();
+ private DeviceId id1;
+
+
+ @Before
+ public void setUp() {
+ devicePortStatsCommand = new DevicePortStatsCommand();
+
+ id1 = NetTestTools.did("d1");
+
+ DefaultDevice d1 = new DefaultDevice(NetTestTools.PID, id1, Device.Type.SWITCH,
+ "test", "1.0", "1.0",
+ "abacab", new ChassisId("c"),
+ DefaultAnnotations.EMPTY);
+
+ devices.add(d1);
+
+ portStatistics = DefaultPortStatistics.builder()
+ .setDurationSec(1)
+ .setBytesReceived(10)
+ .setBytesSent(20)
+ .setDurationNano(30)
+ .setPacketsReceived(40)
+ .setPacketsSent(50)
+ .setPacketsRxDropped(60)
+ .setPacketsRxErrors(70)
+ .setPacketsTxDropped(80)
+ .setPacketsTxErrors(90)
+ .setPort(PortNumber.portNumber(81))
+ .setDeviceId(id1)
+ .build();
+
+ portStatisticsList.add(portStatistics);
+
+ deviceService = createMock(DeviceService.class);
+ expect(deviceService.getPortStatistics(id1))
+ .andReturn(portStatisticsList);
+ expect(deviceService.getPortDeltaStatistics(id1))
+ .andReturn(portStatisticsList);
+
+ replay(deviceService);
+ }
+
+
+ /**
+ * Tests json port stats output.
+ */
+ @Test
+ public void testJsonPortStats() {
+
+ JsonNode node = devicePortStatsCommand.jsonPortStats(deviceService, devices).get(0);
+
+ assertEquals(node.findValue("deviceId").asText(), id1.toString());
+ assertEquals(node.findValue("port").asText(), portStatistics.portNumber().toString());
+ assertEquals(node.findValue("pktRx").asLong(), portStatistics.packetsReceived());
+ assertEquals(node.findValue("pktTx").asLong(), portStatistics.packetsSent());
+ assertEquals(node.findValue("bytesRx").asLong(), portStatistics.bytesReceived());
+ assertEquals(node.findValue("bytesTx").asLong(), portStatistics.bytesSent());
+ assertEquals(node.findValue("pktRxDrp").asLong(), portStatistics.packetsRxDropped());
+ assertEquals(node.findValue("pktTxDrp").asLong(), portStatistics.packetsTxDropped());
+ assertEquals(node.findValue("Dur").asLong(), portStatistics.durationSec());
+
+ }
+
+ /**
+ * Tests json port stats delta output.
+ */
+ @Test
+ public void testJsonPortStatsDelta() {
+
+ JsonNode node = devicePortStatsCommand.jsonPortStatsDelta(deviceService, devices).get(0);
+
+ float duration = ((float) portStatistics.durationSec()) +
+ (((float) portStatistics.durationNano()) / TimeUnit.SECONDS.toNanos(1));
+ float rateRx = portStatistics.bytesReceived() * 8 / duration;
+ float rateTx = portStatistics.bytesSent() * 8 / duration;
+
+ assertEquals(node.findValue("deviceId").asText(), id1.toString());
+ assertEquals(node.findValue("port").asText(), portStatistics.portNumber().toString());
+ assertEquals(node.findValue("pktRx").asLong(), portStatistics.packetsReceived());
+ assertEquals(node.findValue("pktTx").asLong(), portStatistics.packetsSent());
+ assertEquals(node.findValue("bytesRx").asLong(), portStatistics.bytesReceived());
+ assertEquals(node.findValue("bytesTx").asLong(), portStatistics.bytesSent());
+ assertEquals(node.findValue("rateRx").asText(), String.format("%.1f", rateRx));
+ assertEquals(node.findValue("rateTx").asText(), String.format("%.1f", rateTx));
+ assertEquals(node.findValue("pktRxDrp").asLong(), portStatistics.packetsRxDropped());
+ assertEquals(node.findValue("pktTxDrp").asLong(), portStatistics.packetsTxDropped());
+ assertEquals(node.findValue("interval").asText(), String.format("%.3f", duration));
+
+ }
+}
diff --git a/cli/src/test/java/org/onosproject/cli/net/package-info.java b/cli/src/test/java/org/onosproject/cli/net/package-info.java
new file mode 100644
index 0000000..a46b087
--- /dev/null
+++ b/cli/src/test/java/org/onosproject/cli/net/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Test Administrative console command-line extensions for interacting with the
+ * network model & services.
+ */
+package org.onosproject.cli.net;
\ No newline at end of file
diff --git a/cli/src/test/java/org/onosproject/cli/package-info.java b/cli/src/test/java/org/onosproject/cli/package-info.java
new file mode 100644
index 0000000..212c946
--- /dev/null
+++ b/cli/src/test/java/org/onosproject/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Administrative console command-line extensions test.
+ */
+package org.onosproject.cli;
\ No newline at end of file