Initializes gateway type of kubevirt node.

Change-Id: Ib48f54f60fa82b5fe35f0077687653712fd22803
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodec.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodec.java
index 4a7e77c..f1ea1c9 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodec.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodec.java
@@ -51,6 +51,7 @@
     private static final String TUNNEL_BRIDGE = "tunnelBridge";
     private static final String STATE = "state";
     private static final String PHYSICAL_INTERFACES = "phyIntfs";
+    private static final String GATEWAY_BRIDGE_NAME = "gatewayBridgeName";
 
     private static final String MISSING_MESSAGE = " is required in OpenstackNode";
 
@@ -90,6 +91,11 @@
             result.set(PHYSICAL_INTERFACES, phyIntfs);
         }
 
+        // serialize external bridge if exist
+        if (node.gatewayBridgeName() != null) {
+            result.put(GATEWAY_BRIDGE_NAME, node.gatewayBridgeName());
+        }
+
         return result;
     }
 
@@ -140,6 +146,11 @@
         }
         nodeBuilder.phyIntfs(phyIntfs);
 
+        JsonNode externalBridgeJson = json.get(GATEWAY_BRIDGE_NAME);
+        if (externalBridgeJson != null) {
+            nodeBuilder.gatewayBridgeName(externalBridgeJson.asText());
+        }
+
         log.trace("node is {}", nodeBuilder.build().toString());
 
         return nodeBuilder.build();
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtApiConfigHandler.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtApiConfigHandler.java
index 7208cd6..27866d4 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtApiConfigHandler.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtApiConfigHandler.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.kubevirtnode.impl;
 
-import io.fabric8.kubernetes.api.model.Node;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.LeadershipService;
@@ -26,7 +25,6 @@
 import org.onosproject.kubevirtnode.api.KubevirtApiConfigAdminService;
 import org.onosproject.kubevirtnode.api.KubevirtApiConfigEvent;
 import org.onosproject.kubevirtnode.api.KubevirtApiConfigListener;
-import org.onosproject.kubevirtnode.api.KubevirtNode;
 import org.onosproject.kubevirtnode.api.KubevirtNodeAdminService;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -42,8 +40,6 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.kubevirtnode.api.KubevirtApiConfig.State.CONNECTED;
 import static org.onosproject.kubevirtnode.api.KubevirtApiConfigService.APP_ID;
-import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
-import static org.onosproject.kubevirtnode.util.KubevirtNodeUtil.buildKubevirtNode;
 import static org.onosproject.kubevirtnode.util.KubevirtNodeUtil.k8sClient;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -110,26 +106,6 @@
         return k8sClient != null && k8sClient.getApiVersion() != null;
     }
 
-    private void bootstrapKubevirtNodes(KubevirtApiConfig config) {
-        KubernetesClient k8sClient = k8sClient(config);
-
-        if (k8sClient == null) {
-            log.warn("Failed to connect to kubernetes API server");
-            return;
-        }
-
-        for (Node node : k8sClient.nodes().list().getItems()) {
-            KubevirtNode kubevirtNode = buildKubevirtNode(node);
-            // we always provision VMs to worker nodes, so only need to install
-            // flow rules in worker nodes
-            if (kubevirtNode.type() == WORKER) {
-                if (!nodeAdminService.hasNode(kubevirtNode.hostname())) {
-                    nodeAdminService.createNode(kubevirtNode);
-                }
-            }
-        }
-    }
-
     private class InternalKubevirtApiConfigListener implements KubevirtApiConfigListener {
 
         private boolean isRelevantHelper() {
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeWatcher.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeWatcher.java
index 89086bf..4ac793d 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeWatcher.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeWatcher.java
@@ -43,6 +43,7 @@
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
 import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
 import static org.onosproject.kubevirtnode.api.KubevirtNodeService.APP_ID;
 import static org.onosproject.kubevirtnode.api.KubevirtNodeState.INIT;
@@ -187,7 +188,7 @@
                     node.getMetadata().getName());
 
             KubevirtNode kubevirtNode = buildKubevirtNode(node);
-            if (kubevirtNode.type() == WORKER) {
+            if (kubevirtNode.type() == WORKER || kubevirtNode.type() == GATEWAY) {
                 if (!kubevirtNodeAdminService.hasNode(kubevirtNode.hostname())) {
                     kubevirtNodeAdminService.createNode(kubevirtNode);
                 }
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java
index 06ccc31..f11547f 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java
@@ -15,6 +15,9 @@
  */
 package org.onosproject.kubevirtnode.util;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Strings;
 import io.fabric8.kubernetes.api.model.Node;
@@ -53,6 +56,7 @@
 
 import static org.onlab.util.Tools.get;
 import static org.onosproject.kubevirtnode.api.Constants.SONA_PROJECT_DOMAIN;
+import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
 import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.MASTER;
 import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
 
@@ -73,6 +77,8 @@
     private static final String K8S_ROLE = "node-role.kubernetes.io";
     private static final String PHYSNET_CONFIG_KEY = SONA_PROJECT_DOMAIN + "/physnet-config";
     private static final String DATA_IP_KEY = SONA_PROJECT_DOMAIN + "/data-ip";
+    private static final String GATEWAY_CONFIG_KEY = SONA_PROJECT_DOMAIN + "/gateway-config";
+    private static final String GATEWAY_BRIDGE_NAME = "gatewayBridgeName";
     private static final String NETWORK_KEY = "network";
     private static final String INTERFACE_KEY = "interface";
 
@@ -336,8 +342,10 @@
         // start to parse kubernetes annotation
         Map<String, String> annots = node.getMetadata().getAnnotations();
         String physnetConfig = annots.get(PHYSNET_CONFIG_KEY);
+        String gatewayConfig = annots.get(GATEWAY_CONFIG_KEY);
         String dataIpStr = annots.get(DATA_IP_KEY);
         Set<KubevirtPhyInterface> phys = new HashSet<>();
+        String gatewayBridgeName = null;
         try {
             if (physnetConfig != null) {
                 JSONArray configJson = new JSONArray(physnetConfig);
@@ -351,15 +359,25 @@
                         phys.add(DefaultKubevirtPhyInterface.builder()
                                 .network(network).intf(intf).build());
                     }
-
                 }
             }
 
             if (dataIpStr != null) {
                 dataIp = IpAddress.valueOf(dataIpStr);
             }
+
+            if (gatewayConfig != null) {
+                JsonNode jsonNode = new ObjectMapper().readTree(gatewayConfig);
+
+                nodeType = GATEWAY;
+                gatewayBridgeName = jsonNode.get(GATEWAY_BRIDGE_NAME).asText();
+            }
         } catch (JSONException e) {
-            log.error("Failed to parse network status object", e);
+            log.error("Failed to parse physnet config or gateway config object because of{}", e);
+        } catch (JsonMappingException e) {
+            log.error("Failed to parse physnet config or gateway config object because of{}", e);
+        } catch (JsonProcessingException e) {
+            log.error("Failed to parse physnet config or gateway config object because of{}", e);
         }
 
         return DefaultKubevirtNode.builder()
@@ -369,6 +387,7 @@
                 .type(nodeType)
                 .state(KubevirtNodeState.ON_BOARDED)
                 .phyIntfs(phys)
+                .gatewayBridgeName(gatewayBridgeName)
                 .build();
     }
 }
diff --git a/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java b/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java
index 93d53af..eee6bf7 100644
--- a/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java
+++ b/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java
@@ -142,6 +142,44 @@
     }
 
     /**
+     * Tests the kubevirt gateway node encoding.
+     */
+    @Test
+    public void testKubevirtGatweayNodeEncode() {
+        KubevirtNode node = DefaultKubevirtNode.builder()
+                .hostname("gateway")
+                .type(KubevirtNode.Type.GATEWAY)
+                .state(KubevirtNodeState.INIT)
+                .managementIp(IpAddress.valueOf("10.10.10.1"))
+                .intgBridge(DeviceId.deviceId("br-int"))
+                .tunBridge(DeviceId.deviceId("br-tun"))
+                .dataIp(IpAddress.valueOf("20.20.20.2"))
+                .gatewayBridgeName("gateway")
+                .build();
+
+        ObjectNode nodeJson = kubevirtNodeCodec.encode(node, context);
+        assertThat(nodeJson, matchesKubevirtNode(node));
+    }
+
+    /**
+     * Tests the kubevirt gateway node decoding.
+     *
+     * @throws IOException io exception
+     */
+    @Test
+    public void testKubevirtGatewayNodeDecode() throws IOException {
+        KubevirtNode node = getKubevirtNode("KubevirtGatewayNode.json");
+
+        assertThat(node.hostname(), is("gateway-01"));
+        assertThat(node.type().name(), is("GATEWAY"));
+        assertThat(node.managementIp().toString(), is("172.16.130.4"));
+        assertThat(node.dataIp().toString(), is("172.16.130.4"));
+        assertThat(node.intgBridge().toString(), is("of:00000000000000a1"));
+        assertThat(node.tunBridge().toString(), is("of:00000000000000a2"));
+        assertThat(node.gatewayBridgeName(), is("gateway"));
+    }
+
+    /**
      * Mock codec context for use in codec unit tests.
      */
     private class MockCodecContext implements CodecContext {
diff --git a/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtGatewayNode.json b/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtGatewayNode.json
new file mode 100644
index 0000000..1284fec
--- /dev/null
+++ b/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtGatewayNode.json
@@ -0,0 +1,9 @@
+{
+  "hostname": "gateway-01",
+  "type": "GATEWAY",
+  "managementIp": "172.16.130.4",
+  "dataIp": "172.16.130.4",
+  "integrationBridge": "of:00000000000000a1",
+  "tunnelBridge": "of:00000000000000a2",
+  "gatewayBridgeName": "gateway"
+}
\ No newline at end of file