[ONOS-7704] device memory/cpu stats for pica8 switch using Switch_Inventory DB

Change-Id: I1956d06ab373119da59561252f5b35561f8f5619
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
index dfa1518..d552a70 100644
--- a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
@@ -17,11 +17,14 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.behaviour.DeviceCpuStats;
+import org.onosproject.net.behaviour.DeviceMemoryStats;
 import org.onosproject.net.behaviour.MirroringName;
 import org.onosproject.net.behaviour.MirroringStatistics;
 import org.onosproject.net.behaviour.QosId;
@@ -33,6 +36,7 @@
 import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
 
 import com.google.common.util.concurrent.ListenableFuture;
+import org.onosproject.ovsdb.rfc.table.OvsdbTable;
 
 /**
  * Represents to provider facing side of a node.
@@ -372,4 +376,27 @@
      * @return errorstatus true if input port list contains error, false otherwise
      */
     boolean getPortError(List<OvsdbPortName>  portNames, DeviceId bridgeId);
+
+    /**
+     * Gets First row for the given table of given DB.
+     *
+     * @param dbName  db name
+     * @param tblName table name
+     * @return first table entry
+     */
+
+    public Optional<Object> getFirstRow(String dbName, OvsdbTable tblName);
+
+    /**
+     * Gets device CPU usage in percentage.
+     * @return device memory usage.
+     */
+    Optional<DeviceCpuStats> getDeviceCpuUsage();
+
+    /**
+     * Gets device memory usage in kilobytes.
+     * @return device memory usage.
+     */
+    Optional<DeviceMemoryStats> getDeviceMemoryUsage();
+
 }
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
index 6919461..12447e3 100644
--- a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
@@ -112,4 +112,16 @@
     public static final int OFPORT_ERROR = -1;
 
     public static final boolean SERVER_MODE = true;
+
+    /** Ovsdb database Switch_Inventory. */
+    public static final String SWINVENTORY_DBNAME = "Switch_Inventory";
+
+    /** Cpu_Memory_Data table. */
+    public static final String CPU_MEMORY_DATA = "Cpu_Memory_Data";
+
+    /** Cpu column of Cpu_Memory_Data table. */
+    public static final String DEVICE_CPU = "cpu";
+
+    /** Memory column of Cpu_Memory_Data table. */
+    public static final String DEVICE_MEMORY = "memory";
 }
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
index 17d931f..38f8ede 100644
--- a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
@@ -31,6 +31,8 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.ControlProtocolVersion;
 import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.behaviour.DeviceCpuStats;
+import org.onosproject.net.behaviour.DeviceMemoryStats;
 import org.onosproject.net.behaviour.MirroringName;
 import org.onosproject.net.behaviour.MirroringStatistics;
 import org.onosproject.net.behaviour.QosId;
@@ -1871,4 +1873,66 @@
                 .filter(intf -> Objects.nonNull(intf) && portName.equalsIgnoreCase(intf.getName()))
                 .findFirst().orElse(null);
     }
+
+    /**
+     * Get first row of given table from given db.
+     *
+     * @param dbName  db name
+     * @param tblName table name
+     * @return firstRow, first row of the given table from given db if present
+     */
+    @Override
+    public Optional<Object> getFirstRow(String dbName, OvsdbTable tblName) {
+
+        DatabaseSchema dbSchema = getDatabaseSchema(dbName);
+        if (Objects.isNull(dbSchema)) {
+            return Optional.empty();
+        }
+
+        OvsdbTableStore tableStore = ovsdbStore.getOvsdbTableStore(dbName);
+        if (tableStore == null) {
+            return Optional.empty();
+        }
+        OvsdbRowStore rowStore = tableStore.getRows(tblName.tableName());
+        if (rowStore == null) {
+            return Optional.empty();
+        }
+
+        ConcurrentMap<String, Row> rows = rowStore.getRowStore();
+        if (rows == null) {
+            log.debug("The {} Table Rows is null", tblName);
+            return Optional.empty();
+        }
+
+        // There should be only 1 row in this table
+        Optional<String> uuid = rows.keySet().stream().findFirst();
+        if (uuid.isPresent() && rows.containsKey(uuid.get())) {
+            return Optional.of(TableGenerator.getTable(dbSchema,
+                    rows.get(uuid.get()), tblName));
+        } else {
+            return Optional.empty();
+        }
+    }
+
+
+    /**
+     * Get memory usage of device.
+     *
+     * @return memoryStats, empty data as there is no generic way to fetch such stats
+     */
+    @Override
+    public Optional<DeviceMemoryStats> getDeviceMemoryUsage() {
+        return Optional.empty();
+    }
+
+
+    /**
+     * Get cpu usage of device.
+     *
+     * @return cpuStats, empty data as there is no generic way to fetch such stats
+     */
+    @Override
+    public Optional<DeviceCpuStats> getDeviceCpuUsage() {
+        return Optional.empty();
+    }
 }
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/PicaOvsdbClient.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/PicaOvsdbClient.java
new file mode 100644
index 0000000..a5a33d1
--- /dev/null
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/PicaOvsdbClient.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015-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.ovsdb.controller.driver;
+
+
+import org.onosproject.net.behaviour.DeviceCpuStats;
+import org.onosproject.net.behaviour.DeviceMemoryStats;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.rfc.table.CpuMemoryData;
+import org.onosproject.ovsdb.rfc.table.OvsdbTable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+import static org.onosproject.ovsdb.controller.OvsdbConstant.*;
+import static org.onosproject.ovsdb.controller.OvsdbConstant.SWINVENTORY_DBNAME;
+
+/**
+ * A representation of an ovsdb client for Pica device.
+ */
+public final class PicaOvsdbClient {
+
+    private final Logger log = LoggerFactory.getLogger(DefaultOvsdbClient.class);
+
+    private OvsdbClientService ovsdbClientService;
+
+    /**
+     * Creates an OvsdbClient for pica device.
+     *
+     * @param ovsdbClient default ovsdb client
+     */
+    public PicaOvsdbClient(OvsdbClientService ovsdbClient) {
+        this.ovsdbClientService = ovsdbClient;
+    }
+
+    /**
+     * Get memory usage of pica device.
+     *
+     * @return memoryStats, memory usage statistics if present
+     */
+    public Optional<DeviceMemoryStats> getDeviceMemoryUsage() {
+
+        Optional<Object> deviceMemoryDataObject = ovsdbClientService.getFirstRow(
+                SWINVENTORY_DBNAME, OvsdbTable.CPUMEMORYDATA);
+
+        if (!deviceMemoryDataObject.isPresent()) {
+            log.debug("Could not find {} column in {} table", DEVICE_MEMORY, CPU_MEMORY_DATA);
+            return Optional.empty();
+        }
+        CpuMemoryData deviceMemoryData = (CpuMemoryData) deviceMemoryDataObject.get();
+
+        long totalMem = deviceMemoryData.getTotalMemoryStats();
+        long usedMem = deviceMemoryData.getUsedMemoryStats();
+        long freeMem = deviceMemoryData.getFreeMemoryStats();
+
+        DeviceMemoryStats deviceMemoryStats = new DeviceMemoryStats();
+        deviceMemoryStats.setFree(freeMem);
+        deviceMemoryStats.setUsed(usedMem);
+        deviceMemoryStats.setTotal(totalMem);
+
+        return Optional.of(deviceMemoryStats);
+    }
+
+    /**
+     * Get cpu usage of pica device.
+     *
+     * @return cpuStats, cpu usage statistics if present
+     */
+    public Optional<DeviceCpuStats> getDeviceCpuUsage() {
+
+        Optional<Object> deviceCpuDataObject = ovsdbClientService.getFirstRow(
+                SWINVENTORY_DBNAME, OvsdbTable.CPUMEMORYDATA);
+
+        if (!deviceCpuDataObject.isPresent()) {
+            log.debug("Could not find {} column in {} table", DEVICE_CPU, CPU_MEMORY_DATA);
+            return Optional.empty();
+        }
+        CpuMemoryData deviceCpuData = (CpuMemoryData) deviceCpuDataObject.get();
+
+        log.debug("GOT CpuMemoryData as {} ", deviceCpuData);
+
+        float freeCpuStat = deviceCpuData.getFreeCpuStats();
+        DeviceCpuStats deviceCpuStats = new DeviceCpuStats();
+        deviceCpuStats.setUsed(100.0f - freeCpuStat);
+        return Optional.of(deviceCpuStats);
+    }
+}