Fixes openstack purge rules CLI operate based hostnames

Change-Id: I6f7070013c792ed8b10d711ed9722c8df4bab791
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeRulesCommand.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeRulesCommand.java
index c9def05..589ff2a 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeRulesCommand.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeRulesCommand.java
@@ -15,17 +15,24 @@
  */
 package org.onosproject.openstacknetworking.cli;
 
+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.onosproject.cli.AbstractShellCommand;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import static java.lang.Thread.sleep;
 import static java.util.stream.StreamSupport.stream;
-import static org.onosproject.cli.AbstractShellCommand.get;
 
 /**
  * Purges all existing network states.
@@ -38,53 +45,91 @@
     private static final long TIMEOUT_MS = 10000; // we wait 10s
     private static final long SLEEP_MS = 2000; // we wait 2s for init each node
 
+    @Argument(name = "hostname", description = "Hostname",
+            required = true, multiValued = true)
+    @Completion(OpenstackComputeNodeCompleter.class)
+    private String[] hostnames = null;
+
     @Override
     protected void doExecute() {
         FlowRuleService flowRuleService = get(FlowRuleService.class);
         CoreService coreService = get(CoreService.class);
+        OpenstackNodeService nodeService = get(OpenstackNodeService.class);
         ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
 
         if (appId == null) {
-            error("Failed to purge OpenStack networking flow rules.");
+            error("Failed to purge OpenStack networking flow rules because of null app ID");
+            return;
+        }
+        if (hostnames == null) {
+            error("Failed to purge OpenStack networking flow rules because of null hostnames");
             return;
         }
 
-        flowRuleService.removeFlowRulesById(appId);
-        print("Successfully purged flow rules installed by OpenStack networking app.");
-
-        boolean result = true;
-        long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
-
-        // we make sure all flow rules are removed from the store
-        while (stream(flowRuleService.getFlowEntriesById(appId)
-                                     .spliterator(), false).count() > 0) {
-
-            long  waitMs = timeoutExpiredMs - System.currentTimeMillis();
-
-            try {
-                sleep(SLEEP_MS);
-            } catch (InterruptedException e) {
-                log.error("Exception caused during rule purging...");
+        for (String hostname : hostnames) {
+            if (nodeService.node(hostname) == null) {
+                error("Failed to purge OpenStack networking flow rules for %s because of null openstack node",
+                        hostname);
+                continue;
             }
 
-            if (stream(flowRuleService.getFlowEntriesById(appId)
-                                      .spliterator(), false).count() == 0) {
-                break;
+            DeviceId deviceId = nodeService.node(hostname).intgBridge();
+            if (deviceId == null) {
+                error("Failed to purge OpenStack networking flow rules because of null device ID");
+                return;
+            }
+
+            removeFlowRulesByDeviceId(appId, flowRuleService, deviceId);
+            print("Successfully purged flow rules installed by" +
+                    " OpenStack networking app on host %s.", hostname);
+
+            boolean result = true;
+            long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
+
+            // we make sure all flow rules are removed from the store
+            while (getFlowEntriesByDeviceId(appId, flowRuleService, deviceId).isEmpty()) {
+
+                long waitMs = timeoutExpiredMs - System.currentTimeMillis();
+
+                try {
+                    sleep(SLEEP_MS);
+                } catch (InterruptedException e) {
+                    log.error("Exception caused during rule purging...");
+                }
+
+                if (getFlowEntriesByDeviceId(appId, flowRuleService, deviceId).isEmpty()) {
+                    break;
+                } else {
+                    removeFlowRulesByDeviceId(appId, flowRuleService, deviceId);
+                    print("Failed to purging flow rules, retrying rule purging...");
+                }
+
+                if (waitMs <= 0) {
+                    result = false;
+                    break;
+                }
+            }
+            if (result) {
+                print("Successfully purged flow rules for %s!", hostname);
             } else {
-                flowRuleService.removeFlowRulesById(appId);
-                print("Failed to purging flow rules, retrying rule purging...");
+                error("Failed to purge flow rules for %s.", hostname);
             }
-
-            if (waitMs <= 0) {
-                result = false;
-                break;
-            }
-        }
-
-        if (result) {
-            print("Successfully purged flow rules!");
-        } else {
-            error("Failed to purge flow rules.");
         }
     }
-}
+
+    private void removeFlowRulesByDeviceId(ApplicationId appId,
+                                           FlowRuleService flowRuleService,
+                                           DeviceId deviceId) {
+        stream(flowRuleService.getFlowEntriesById(appId).spliterator(), false)
+                .filter(flowEntry -> flowEntry.deviceId().equals(deviceId))
+                .forEach(flowRuleService::removeFlowRules);
+    }
+
+    private Set<FlowEntry> getFlowEntriesByDeviceId(ApplicationId appId,
+                                                    FlowRuleService flowRuleService,
+                                                    DeviceId deviceId) {
+        return stream(flowRuleService.getFlowEntriesById(appId).spliterator(), false)
+                .filter(flowEntry -> flowEntry.deviceId().equals(deviceId))
+                .collect(Collectors.toSet());
+    }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackVmStatsCommand.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackVmStatsCommand.java
index f551e76..99ce5cb 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackVmStatsCommand.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackVmStatsCommand.java
@@ -16,6 +16,7 @@
 package org.onosproject.openstacknetworking.cli;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
@@ -31,8 +32,10 @@
 import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.openstack4j.model.network.Port;
+
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -65,7 +68,7 @@
     private static final String NO_INSTANCE_PORTS =
             "There's no instance port associated to given VM Device ID";
     private static final String FORMAT =
-            "   port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s, pktRxDrp=%s, pktTxDrp=%s, Dur=%s%s";
+            "   ip address=%s, port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s, pktRxDrp=%s, pktTxDrp=%s, Dur=%s%s";
 
     @Override
     protected void doExecute() {
@@ -93,17 +96,23 @@
         Set<PortNumber> portNumbers =
                 instancePorts.stream().map(InstancePort::portNumber).collect(Collectors.toSet());
 
+        Map<PortNumber, String> ipAddressMap = Maps.newHashMap();
+
+        instancePorts.forEach(instancePort -> {
+
+            ipAddressMap.put(instancePort.portNumber(), instancePort.ipAddress().toString());
+        });
+
         instancePorts.stream().findAny().ifPresent(instancePort -> {
             DeviceId deviceId = instancePort.deviceId();
-
             if (delta) {
-                printPortStatsDelta(vmDeviceId, deviceService.getPortDeltaStatistics(deviceId), portNumbers);
+                printPortStatsDelta(vmDeviceId, ipAddressMap, deviceService.getPortDeltaStatistics(deviceId));
                 if (table) {
                     printPortStatsDeltaTable(
-                            vmDeviceId, deviceService.getPortDeltaStatistics(deviceId), portNumbers);
+                            vmDeviceId, ipAddressMap, deviceService.getPortDeltaStatistics(deviceId));
                 }
             } else {
-                printPortStats(vmDeviceId, deviceService.getPortStatistics(deviceId), portNumbers);
+                printPortStats(vmDeviceId, ipAddressMap, deviceService.getPortStatistics(deviceId));
             }
         });
     }
@@ -118,20 +127,22 @@
     }
 
     private void printPortStatsDelta(String vmDeviceId,
-                                     Iterable<PortStatistics> portStats,
-                                     Set<PortNumber> portNumbers) {
-        final String formatDelta = "   port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s,"
+                                     Map<PortNumber, String> ipAddressMap,
+                                     Iterable<PortStatistics> portStats) {
+        final String formatDelta = "   ip address=%s, port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s,"
                 + " rateRx=%s, rateTx=%s, pktRxDrp=%s, pktTxDrp=%s, interval=%s";
 
         print("VM Device ID: %s", vmDeviceId);
 
         for (PortStatistics stat : sortByPort(portStats)) {
-            if (portNumbers.contains(stat.portNumber())) {
+            if (ipAddressMap.containsKey(stat.portNumber())) {
                 float duration = ((float) stat.durationSec()) +
                         (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
                 float rateRx = stat.bytesReceived() * 8 / duration;
                 float rateTx = stat.bytesSent() * 8 / duration;
-                print(formatDelta, stat.portNumber(),
+                print(formatDelta,
+                        ipAddressMap.get(stat.portNumber()),
+                        stat.portNumber(),
                         stat.packetsReceived(),
                         stat.packetsSent(),
                         stat.bytesReceived(),
@@ -146,25 +157,32 @@
     }
 
     private void printPortStatsDeltaTable(String vmDeviceId,
-                                     Iterable<PortStatistics> portStats,
-                                     Set<PortNumber> portNumbers) {
+                                          Map<PortNumber, String> ipAddressMap,
+                                          Iterable<PortStatistics> portStats) {
 
-        final String formatDeltaTable = "|%5s | %7s | %7s |  %7s | %7s | %7s | %7s |  %7s | %7s |%9s |";
-        print("+---------------------------------------------------------------------------------------------------+");
-        print("| VM Device ID = %-86s |", vmDeviceId);
-        print("|---------------------------------------------------------------------------------------------------|");
-        print("|      | Receive                                | Transmit                               | Time [s] |");
-        print("| Port | Packets |  Bytes  | Rate bps |   Drop  | Packets |  Bytes  | Rate bps |   Drop  | Interval |");
-        print("|---------------------------------------------------------------------------------------------------|");
+        final String formatDeltaTable = "|%15s  |%5s | %7s | %7s |  %7s | %7s | %7s | %7s |  %7s | %7s |%9s |";
+        print("+----------------------------------------------------------------------" +
+                "-----------------------------------------------+");
+        print("| VM Device ID = %-100s |", vmDeviceId);
+        print("|----------------------------------------------------------------------" +
+                "-----------------------------------------------|");
+        print("|                 |      | Receive                                | Transmit    " +
+                "                           | Time [s] |");
+        print("| ip              | Port | Packets |  Bytes  | Rate bps |   Drop  | Packets |  " +
+                "Bytes  | Rate bps |   Drop  | Interval |");
+        print("|----------------------------------------------------------------------" +
+                "-----------------------------------------------|");
 
         for (PortStatistics stat : sortByPort(portStats)) {
 
-            if (portNumbers.contains(stat.portNumber())) {
+            if (ipAddressMap.containsKey(stat.portNumber())) {
                 float duration = ((float) stat.durationSec()) +
                         (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
                 float rateRx = duration > 0 ? stat.bytesReceived() * 8 / duration : 0;
                 float rateTx = duration > 0 ? stat.bytesSent() * 8 / duration : 0;
-                print(formatDeltaTable, stat.portNumber(),
+                print(formatDeltaTable,
+                        ipAddressMap.get(stat.portNumber()),
+                        stat.portNumber(),
                         humanReadable(stat.packetsReceived()),
                         humanReadable(stat.bytesReceived()),
                         humanReadableBps(rateRx),
@@ -176,17 +194,20 @@
                         String.format("%.3f", duration));
             }
         }
-        print("+---------------------------------------------------------------------------------------------------+");
+        print("|----------------------------------------------------------------------" +
+                "-----------------------------------------------|");
 
     }
+
     private void printPortStats(String vmDeviceId,
-                                Iterable<PortStatistics> portStats,
-                                Set<PortNumber> portNumbers) {
+                                Map<PortNumber, String> ipAddressMap,
+                                Iterable<PortStatistics> portStats) {
         print("VM Device ID: %s", vmDeviceId);
 
         for (PortStatistics stat : sortByPort(portStats)) {
-            if (portNumbers.contains(stat.portNumber())) {
-                print(FORMAT, stat.portNumber(), stat.packetsReceived(), stat.packetsSent(), stat.bytesReceived(),
+            if (ipAddressMap.containsKey(stat.portNumber())) {
+                print(FORMAT, ipAddressMap.get(stat.portNumber()),
+                        stat.portNumber(), stat.packetsReceived(), stat.packetsSent(), stat.bytesReceived(),
                         stat.bytesSent(), stat.packetsRxDropped(), stat.packetsTxDropped(), stat.durationSec(),
                         annotations(stat.annotations()));
             }