Support control plane recovery from failure for kubevirt networking

Change-Id: Ic27aa7693d6b4f0c241dc2f3d18d4546e24997d8
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java
index fb2906e..9cc3066 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java
@@ -117,6 +117,27 @@
     }
 
     /**
+     * Reserves the given IP address.
+     *
+     * @param ip IP address to be reserved
+     * @return result for IP address reservation
+     */
+    public synchronized boolean reserveIp(IpAddress ip) {
+        if (availableIps.size() <= 0) {
+            return false;
+        }
+
+        if (allocatedIps.contains(ip) || !availableIps.contains(ip)) {
+            return false;
+        }
+
+        availableIps.remove(ip);
+        allocatedIps.add(ip);
+
+        return true;
+    }
+
+    /**
      * Releases the given IP address.
      *
      * @param ip IP address to be released
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkAdminService.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkAdminService.java
index aeabd84..a8fbf34 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkAdminService.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkAdminService.java
@@ -49,6 +49,15 @@
     IpAddress allocateIp(String networkId);
 
     /**
+     * Reserve the given IP address.
+     *
+     * @param networkId network identifier
+     * @param ip IP address to be reserved
+     * @return reserve result
+     */
+    boolean reserveIp(String networkId, IpAddress ip);
+
+    /**
      * Release the existing IP address.
      *
      * @param networkId network identifier
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java
index d761ff7..cb00052 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.kubevirtnetworking.impl;
 
-
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableSet;
 import org.onlab.packet.IpAddress;
@@ -146,6 +145,22 @@
     }
 
     @Override
+    public boolean reserveIp(String networkId, IpAddress ip) {
+        checkArgument(!Strings.isNullOrEmpty(networkId), ERR_NULL_NETWORK_ID);
+        checkArgument(ip != null, ERR_NULL_IP);
+
+        KubevirtNetwork network = networkStore.network(networkId);
+        boolean result = network.ipPool().reserveIp(ip);
+        if (result) {
+            networkStore.updateNetwork(network);
+        } else {
+            log.warn("Failed to reserve IP address");
+        }
+
+        return result;
+    }
+
+    @Override
     public void releaseIp(String networkId, IpAddress ip) {
         checkArgument(!Strings.isNullOrEmpty(networkId), ERR_NULL_NETWORK_ID);
         checkArgument(ip != null, ERR_NULL_IP);
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtPodPortMapper.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtPodPortMapper.java
index 595b775..d9076da 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtPodPortMapper.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtPodPortMapper.java
@@ -142,12 +142,65 @@
                     eventExecutor.execute(() -> processPodDeletion(event.subject()));
                     break;
                 case KUBEVIRT_POD_CREATED:
+                    eventExecutor.execute(() -> processPodCreation(event.subject()));
+                    break;
                 default:
                     // do nothing
                     break;
             }
         }
 
+        private void processPodCreation(Pod pod) {
+            if (!isRelevantHelper()) {
+                return;
+            }
+
+            KubernetesClient client = k8sClient(kubevirtApiConfigService);
+
+            if (client == null) {
+                return;
+            }
+
+            Map<String, String> annots = pod.getMetadata().getAnnotations();
+            if (annots == null) {
+                return;
+            }
+
+            if (!annots.containsKey(NETWORK_STATUS_KEY)) {
+                return;
+            }
+
+            try {
+                String networkStatusStr = pod.getMetadata().getAnnotations().get(NETWORK_STATUS_KEY);
+                JSONArray networkStatus = new JSONArray(networkStatusStr);
+                for (int i = 0; i < networkStatus.length(); i++) {
+                    JSONObject object = networkStatus.getJSONObject(i);
+                    String name = object.getString(NAME);
+                    KubevirtNetwork jsonNetwork = kubevirtNetworkAdminService.networks().stream()
+                            .filter(n -> (NETWORK_PREFIX + n.name()).equals(name))
+                            .findAny().orElse(null);
+                    if (jsonNetwork != null) {
+                        JSONArray ips = object.getJSONArray(IPS);
+                        if (ips != null && ips.length() > 0) {
+                            IpAddress ip = IpAddress.valueOf(ips.getString(0));
+                            kubevirtNetworkAdminService.reserveIp(jsonNetwork.networkId(), ip);
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.error("Failed to reserve IP address", e);
+            }
+
+            KubevirtPort port = getPort(kubevirtNetworkAdminService.networks(), pod);
+            if (port == null) {
+                return;
+            }
+
+            if (kubevirtPortAdminService.port(port.macAddress()) == null) {
+                kubevirtPortAdminService.createPort(port);
+            }
+        }
+
         private void processPodUpdate(Pod pod) {
             if (!isRelevantHelper()) {
                 return;
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/NetworkAttachmentDefinitionWatcher.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/NetworkAttachmentDefinitionWatcher.java
index 93a3504..bae08bc 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/NetworkAttachmentDefinitionWatcher.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/NetworkAttachmentDefinitionWatcher.java
@@ -293,35 +293,39 @@
                                 IpAddress.valueOf(start), IpAddress.valueOf(end)));
                     }
 
-                    JSONArray routesJson = configJson.getJSONArray(HOST_ROUTES);
-                    Set<KubevirtHostRoute> hostRoutes = new HashSet<>();
-                    if (routesJson != null) {
-                        for (int i = 0; i < routesJson.length(); i++) {
-                            JSONObject route = routesJson.getJSONObject(i);
-                            String destinationStr = route.getString(DESTINATION);
-                            String nexthopStr = route.getString(NEXTHOP);
+                    if (configJson.has(HOST_ROUTES)) {
+                        JSONArray routesJson = configJson.getJSONArray(HOST_ROUTES);
+                        Set<KubevirtHostRoute> hostRoutes = new HashSet<>();
+                        if (routesJson != null) {
+                            for (int i = 0; i < routesJson.length(); i++) {
+                                JSONObject route = routesJson.getJSONObject(i);
+                                String destinationStr = route.getString(DESTINATION);
+                                String nexthopStr = route.getString(NEXTHOP);
 
-                            if (StringUtils.isNotEmpty(destinationStr) &&
-                                    StringUtils.isNotEmpty(nexthopStr)) {
-                                hostRoutes.add(new KubevirtHostRoute(
-                                        IpPrefix.valueOf(destinationStr),
-                                        IpAddress.valueOf(nexthopStr)));
+                                if (StringUtils.isNotEmpty(destinationStr) &&
+                                        StringUtils.isNotEmpty(nexthopStr)) {
+                                    hostRoutes.add(new KubevirtHostRoute(
+                                            IpPrefix.valueOf(destinationStr),
+                                            IpAddress.valueOf(nexthopStr)));
+                                }
                             }
                         }
+                        builder.hostRoutes(hostRoutes);
                     }
-                    builder.hostRoutes(hostRoutes);
 
-                    JSONArray dnsesJson = configJson.getJSONArray(DNSES);
-                    Set<IpAddress> dnses = new HashSet<>();
-                    if (dnsesJson != null) {
-                        for (int i = 0; i < dnsesJson.length(); i++) {
-                             String dns = dnsesJson.getString(i);
-                             if (StringUtils.isNotEmpty(dns)) {
-                                 dnses.add(IpAddress.valueOf(dns));
-                             }
+                    if (configJson.has(DNSES)) {
+                        JSONArray dnsesJson = configJson.getJSONArray(DNSES);
+                        Set<IpAddress> dnses = new HashSet<>();
+                        if (dnsesJson != null) {
+                            for (int i = 0; i < dnsesJson.length(); i++) {
+                                String dns = dnsesJson.getString(i);
+                                if (StringUtils.isNotEmpty(dns)) {
+                                    dnses.add(IpAddress.valueOf(dns));
+                                }
+                            }
                         }
+                        builder.dnses(dnses);
                     }
-                    builder.dnses(dnses);
 
                     builder.networkId(name).name(name).type(Type.valueOf(type))
                             .mtu(mtu).gatewayIp(IpAddress.valueOf(gatewayIp)).cidr(cidr);
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/KubevirtNetworkingUtil.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/KubevirtNetworkingUtil.java
index d9ea01e..db54054 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/KubevirtNetworkingUtil.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/KubevirtNetworkingUtil.java
@@ -262,6 +262,10 @@
                 return null;
             }
 
+            if (!annots.containsKey(NETWORK_STATUS_KEY)) {
+                return null;
+            }
+
             String networkStatusStr = annots.get(NETWORK_STATUS_KEY);
 
             if (networkStatusStr == null) {
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/OsgiPropertyConstants.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/OsgiPropertyConstants.java
index 9c1b8f8..0891d8c 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/OsgiPropertyConstants.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/OsgiPropertyConstants.java
@@ -24,7 +24,7 @@
     }
 
     static final String OVSDB_PORT = "ovsdbPortNum";
-    static final int OVSDB_PORT_NUM_DEFAULT = 6653;
+    static final int OVSDB_PORT_NUM_DEFAULT = 6650;
 
     static final String AUTO_RECOVERY = "autoRecovery";
     static final boolean AUTO_RECOVERY_DEFAULT = true;