[ONOS-5432] Add CLI for refresh/reprogram the data plane for the existing VM.

- Add CLI to purge flow rules installed by openstack apps.
- Add CLI to reinstall flow rules for the existing virtual instances.
- Remove CREATE_TIME from host annotation and revert to use host as a key of security group rule map.

Change-Id: Ie647e5a8c86e86deb8ff050ecf280527ad218eda
diff --git a/apps/openstacknetworking/switching/BUCK b/apps/openstacknetworking/switching/BUCK
index 5e991af..cbb3ec4 100644
--- a/apps/openstacknetworking/switching/BUCK
+++ b/apps/openstacknetworking/switching/BUCK
@@ -10,6 +10,7 @@
 BUNDLES = [
     '//apps/openstacknetworking/api:onos-apps-openstacknetworking-api',
     '//apps/openstacknetworking/web:onos-apps-openstacknetworking-web',
+    '//apps/openstacknetworking/cli:onos-apps-openstacknetworking-cli',
     '//apps/openstacknetworking/switching:onos-apps-openstacknetworking-switching',
 ]
 
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java
index 9794401..1cc6ef5 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java
@@ -33,7 +33,6 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
@@ -79,9 +78,7 @@
     private static final String PROTO_UDP = "UDP";
     private static final String ETHTYPE_IPV4 = "IPV4";
 
-    private final Map<HostId, Set<SecurityGroupRule>> securityGroupRuleMap = Maps.newConcurrentMap();
-    private final Map<HostId, Host> hostInfoMap = Maps.newHashMap();
-
+    private final Map<Host, Set<SecurityGroupRule>> securityGroupRuleMap = Maps.newConcurrentMap();
     private ApplicationId appId;
 
     @Activate
@@ -121,9 +118,9 @@
      */
     private void populateSecurityGroupRules(String tenantId, boolean install) {
         securityGroupRuleMap.entrySet().stream()
-                .filter(entry -> getTenantId(hostInfoMap.get(entry.getKey())).equals(tenantId))
+                .filter(entry -> getTenantId(entry.getKey()).equals(tenantId))
                 .forEach(entry -> {
-                    Host local = hostInfoMap.get(entry.getKey());
+                    Host local = entry.getKey();
                     entry.getValue().forEach(sgRule -> {
                         setSecurityGroupRule(local.location().deviceId(),
                                 sgRule.rule(),
@@ -262,8 +259,7 @@
                 log.warn("Failed to get security group {}", sgId);
             }
         });
-        hostInfoMap.put(host.id(), host);
-        securityGroupRuleMap.put(host.id(), rules);
+        securityGroupRuleMap.put(host, rules);
     }
 
     /**
@@ -297,11 +293,11 @@
     private Set<IpPrefix> getRemoteIps(String tenantId, String sgId) {
         Set<IpPrefix> remoteIps = Sets.newHashSet();
         securityGroupRuleMap.entrySet().stream()
-                .filter(entry -> Objects.equals(getTenantId(hostInfoMap.get(entry.getKey())), tenantId))
+                .filter(entry -> Objects.equals(getTenantId(entry.getKey()), tenantId))
                 .forEach(entry -> {
                     if (entry.getValue().stream()
                             .anyMatch(rule -> rule.rule().secuityGroupId().equals(sgId))) {
-                        remoteIps.add(IpPrefix.valueOf(getIp(hostInfoMap.get(entry.getKey())), 32));
+                        remoteIps.add(IpPrefix.valueOf(getIp(entry.getKey()), 32));
                     }
                 });
         return remoteIps;
@@ -314,8 +310,7 @@
         if (isHostAdded) {
             updateSecurityGroupRulesMap(host);
         } else {
-            securityGroupRuleMap.remove(host.id());
-            hostInfoMap.remove(host.id());
+            securityGroupRuleMap.remove(host);
         }
 
         Tools.stream(hostService.getHosts())
@@ -337,6 +332,59 @@
         log.info("Applied security group rules for {}", host);
     }
 
+    @Override
+    public void reinstallVmFlow(Host host) {
+        if (host == null) {
+            hostService.getHosts().forEach(h -> {
+                updateSecurityGroupRules(h, true);
+                log.info("Re-Install data plane flow of virtual machine {}", h);
+            });
+        } else {
+            securityGroupRuleMap.entrySet().stream()
+                .filter(entry -> entry.getKey().id().equals(host.id()))
+                .forEach(entry -> {
+                    Host local = entry.getKey();
+                    entry.getValue().forEach(sgRule -> {
+                        setSecurityGroupRule(local.location().deviceId(),
+                                sgRule.rule(),
+                                getIp(local),
+                                sgRule.remoteIp(), true);
+                    });
+                });
+            log.info("Re-Install data plane flow of virtual machine {}", host);
+        }
+    }
+
+    @Override
+    public void purgeVmFlow(Host host) {
+        if (host == null) {
+            securityGroupRuleMap.entrySet().stream()
+                .forEach(entry -> {
+                    Host local = entry.getKey();
+                    entry.getValue().forEach(sgRule -> {
+                        setSecurityGroupRule(local.location().deviceId(),
+                                sgRule.rule(),
+                                getIp(local),
+                                sgRule.remoteIp(), false);
+                    });
+                    log.info("Purge data plane flow of virtual machine {}", local);
+                });
+        } else {
+            securityGroupRuleMap.entrySet().stream()
+                .filter(entry -> entry.getKey().id().equals(host.id()))
+                .forEach(entry -> {
+                    Host local = entry.getKey();
+                    entry.getValue().forEach(sgRule -> {
+                        setSecurityGroupRule(local.location().deviceId(),
+                                sgRule.rule(),
+                                getIp(local),
+                                sgRule.remoteIp(), false);
+                    });
+                });
+            log.info("Purge data plane flow of virtual machine {}", host);
+        }
+    }
+
     private final class SecurityGroupRule {
         private final OpenstackSecurityGroupRule rule;
         private final IpPrefix remoteIp;
@@ -375,4 +423,4 @@
             return Objects.hash(rule, remoteIp);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java
index 0228af7..8bec3d1 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java
@@ -175,9 +175,6 @@
         registerDhcpInfo(osPort, openstackSubnet);
         ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
 
-
-        // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
-        // existing instances.
         DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
                 .set(NETWORK_ID, osPort.networkId())
                 .set(SUBNET_ID, fixedIp.getKey())
@@ -185,8 +182,7 @@
                 .set(VXLAN_ID, osNet.segmentId())
                 .set(TENANT_ID, osNet.tenantId())
                 // TODO remove gateway IP from host annotation
-                .set(GATEWAY_IP, openstackSubnet.gatewayIp())
-                .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
+                .set(GATEWAY_IP, openstackSubnet.gatewayIp());
 
         HostDescription hostDesc = new DefaultHostDescription(
                 osPort.macAddress(),
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
index 59b41ff..db324d7 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
@@ -21,6 +21,7 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
@@ -36,6 +37,7 @@
 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
 import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.openstacknetworking.OpenstackSwitchingService;
 import org.onosproject.openstacknetworking.AbstractVmHandler;
 import org.onosproject.openstacknode.OpenstackNodeService;
 import org.slf4j.Logger;
@@ -47,11 +49,14 @@
 import static org.onosproject.openstacknetworking.Constants.*;
 import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
 
+
 /**
  * Populates switching flow rules.
  */
+@Service
 @Component(immediate = true)
-public final class OpenstackSwitchingManager extends AbstractVmHandler {
+public final class OpenstackSwitchingManager extends AbstractVmHandler
+        implements OpenstackSwitchingService {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -270,4 +275,30 @@
         removeSwitchingRules(host);
         log.info("Removed virtual machine from switching service {}", host);
     }
+
+    @Override
+    public void reinstallVmFlow(Host host) {
+        if (host == null) {
+            hostService.getHosts().forEach(h -> {
+                populateSwitchingRules(h);
+                log.info("Re-Install data plane flow of virtual machine {}", h);
+            });
+        } else {
+            populateSwitchingRules(host);
+            log.info("Re-Install data plane flow of virtual machine {}", host);
+        }
+    }
+
+    @Override
+    public void purgeVmFlow(Host host) {
+        if (host == null) {
+            hostService.getHosts().forEach(h -> {
+                removeSwitchingRules(h);
+                log.info("Purge data plane flow of virtual machine {}", h);
+            });
+        } else {
+            removeSwitchingRules(host);
+            log.info("Purge data plane flow of virtual machine {}", host);
+        }
+    }
 }