Add keystone and neutron config classes and codec with unit tests

Change-Id: Ia89f5be9bac88927a383d56d56413ba23e3e5eb3
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/KeystoneConfigCodec.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/KeystoneConfigCodec.java
new file mode 100644
index 0000000..95da63a
--- /dev/null
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/KeystoneConfigCodec.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018-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.openstacknode.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstacknode.api.KeystoneConfig;
+import org.onosproject.openstacknode.api.OpenstackAuth;
+import org.onosproject.openstacknode.api.DefaultKeystoneConfig;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Keystone config codec used for serializing and de-serializing JSON string.
+ */
+public final class KeystoneConfigCodec extends JsonCodec<KeystoneConfig> {
+
+    private static final String ENDPOINT = "endpoint";
+    private static final String AUTHENTICATION = "authentication";
+
+    private static final String MISSING_MESSAGE = " is required in OpenstackNode";
+
+    @Override
+    public ObjectNode encode(KeystoneConfig entity, CodecContext context) {
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(ENDPOINT, entity.endpoint());
+
+        ObjectNode authJson = context.codec(OpenstackAuth.class)
+                .encode(entity.authentication(), context);
+        result.set(AUTHENTICATION, authJson);
+
+        return result;
+    }
+
+    @Override
+    public KeystoneConfig decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        String endpoint = nullIsIllegal(json.get(ENDPOINT).asText(),
+                ENDPOINT + MISSING_MESSAGE);
+
+        // parse authentication
+        JsonNode authJson = nullIsIllegal(json.get(AUTHENTICATION),
+                AUTHENTICATION + MISSING_MESSAGE);
+
+
+        final JsonCodec<OpenstackAuth> authCodec = context.codec(OpenstackAuth.class);
+        OpenstackAuth auth = authCodec.decode((ObjectNode) authJson.deepCopy(), context);
+
+        return DefaultKeystoneConfig.builder()
+                .endpoint(endpoint)
+                .authentication(auth)
+                .build();
+    }
+}
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/NeutronConfigCodec.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/NeutronConfigCodec.java
new file mode 100644
index 0000000..5acf180
--- /dev/null
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/NeutronConfigCodec.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018-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.openstacknode.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstacknode.api.NeutronConfig;
+import org.onosproject.openstacknode.api.DefaultNeutronConfig;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Neutron config codec used for serializing and de-serializing JSON string.
+ */
+public final class NeutronConfigCodec extends JsonCodec<NeutronConfig> {
+
+    private static final String USE_METADATA_PROXY = "useMetadataProxy";
+    private static final String METADATA_PROXY_SECRET = "metadataProxySecret";
+
+    private static final String MISSING_MESSAGE = " is required in OpenstackNode";
+
+    @Override
+    public ObjectNode encode(NeutronConfig entity, CodecContext context) {
+        return context.mapper().createObjectNode()
+                .put(USE_METADATA_PROXY, entity.useMetadataProxy())
+                .put(METADATA_PROXY_SECRET, entity.metadataProxySecret());
+    }
+
+    @Override
+    public NeutronConfig decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        boolean useMetadataProxy = nullIsIllegal(json.get(USE_METADATA_PROXY).asBoolean(),
+                USE_METADATA_PROXY + MISSING_MESSAGE);
+
+        String metadataProxySecret = nullIsIllegal(json.get(METADATA_PROXY_SECRET).asText(),
+                METADATA_PROXY_SECRET + MISSING_MESSAGE);
+
+        return DefaultNeutronConfig.builder()
+                .useMetadataProxy(useMetadataProxy)
+                .metadataProxySecret(metadataProxySecret)
+                .build();
+    }
+}
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
index ad2f08b..d32a071 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
@@ -25,11 +25,14 @@
 import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.openstacknode.api.DefaultOpenstackNode;
 import org.onosproject.openstacknode.api.DpdkConfig;
+import org.onosproject.openstacknode.api.KeystoneConfig;
+import org.onosproject.openstacknode.api.NeutronConfig;
 import org.onosproject.openstacknode.api.NodeState;
 import org.onosproject.openstacknode.api.OpenstackAuth;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackPhyInterface;
 import org.onosproject.openstacknode.api.OpenstackSshAuth;
+import org.onosproject.openstacknode.api.DefaultKeystoneConfig;
 import org.slf4j.Logger;
 
 import java.util.ArrayList;
@@ -59,8 +62,10 @@
     private static final String STATE = "state";
     private static final String PHYSICAL_INTERFACES = "phyIntfs";
     private static final String CONTROLLERS = "controllers";
+    private static final String KEYSTONE_CONFIG = "keystoneConfig";
+    private static final String ENDPOINT = "endpoint";
     private static final String AUTHENTICATION = "authentication";
-    private static final String END_POINT = "endpoint";
+    private static final String NEUTRON_CONFIG = "neutronConfig";
     private static final String SSH_AUTH = "sshAuth";
     private static final String DPDK_CONFIG = "dpdkConfig";
 
@@ -83,7 +88,18 @@
         }
 
         if (type == OpenstackNode.NodeType.CONTROLLER) {
-            result.put(END_POINT, node.endpoint());
+
+            ObjectNode keystoneConfigJson = context.codec(KeystoneConfig.class)
+                    .encode(node.keystoneConfig(), context);
+
+            result.set(KEYSTONE_CONFIG, keystoneConfigJson);
+        }
+
+        if (node.neutronConfig() != null) {
+            ObjectNode neutronConfigJson = context.codec(NeutronConfig.class)
+                    .encode(node.neutronConfig(), context);
+
+            result.set(NEUTRON_CONFIG, neutronConfigJson);
         }
 
         if (node.intgBridge() != null) {
@@ -98,28 +114,21 @@
             result.put(DATA_IP, node.dataIp().toString());
         }
 
-        // TODO: need to find a way to not refer to ServiceDirectory from
-        // DefaultOpenstackNode
-
         ArrayNode phyIntfs = context.mapper().createArrayNode();
         node.phyIntfs().forEach(phyIntf -> {
-            ObjectNode phyIntfJson = context.codec(OpenstackPhyInterface.class).encode(phyIntf, context);
+            ObjectNode phyIntfJson =
+                    context.codec(OpenstackPhyInterface.class).encode(phyIntf, context);
             phyIntfs.add(phyIntfJson);
         });
         result.set(PHYSICAL_INTERFACES, phyIntfs);
 
         ArrayNode controllers = context.mapper().createArrayNode();
         node.controllers().forEach(controller -> {
-            ObjectNode controllerJson = context.codec(ControllerInfo.class).encode(controller, context);
+            ObjectNode controllerJson =
+                    context.codec(ControllerInfo.class).encode(controller, context);
             controllers.add(controllerJson);
         });
 
-        if (node.authentication() != null) {
-            ObjectNode authJson = context.codec(OpenstackAuth.class)
-                    .encode(node.authentication(), context);
-            result.set(AUTHENTICATION, authJson);
-        }
-
         if (node.sshAuthInfo() != null) {
             ObjectNode sshAuthJson = context.codec(OpenstackSshAuth.class)
                     .encode(node.sshAuthInfo(), context);
@@ -159,9 +168,30 @@
                     UPLINK_PORT + MISSING_MESSAGE));
         }
         if (type.equals(CONTROLLER)) {
-            String endPoint = nullIsIllegal(json.get(END_POINT).asText(),
-                    END_POINT + MISSING_MESSAGE);
-            nodeBuilder.endpoint(endPoint);
+
+            JsonNode keystoneConfigJson = json.get(KEYSTONE_CONFIG);
+
+            KeystoneConfig keystoneConfig;
+            if (keystoneConfigJson != null) {
+                final JsonCodec<KeystoneConfig> keystoneConfigCodec =
+                                        context.codec(KeystoneConfig.class);
+                keystoneConfig = keystoneConfigCodec.decode((ObjectNode)
+                                        keystoneConfigJson.deepCopy(), context);
+            } else {
+                JsonNode authJson = json.get(AUTHENTICATION);
+                final JsonCodec<OpenstackAuth> authCodec = context.codec(OpenstackAuth.class);
+                OpenstackAuth auth = authCodec.decode((ObjectNode) authJson.deepCopy(), context);
+
+                String endpoint = nullIsIllegal(json.get(ENDPOINT).asText(),
+                        ENDPOINT + MISSING_MESSAGE);
+
+                keystoneConfig = DefaultKeystoneConfig.builder()
+                        .authentication(auth)
+                        .endpoint(endpoint)
+                        .build();
+            }
+
+            nodeBuilder.keystoneConfig(keystoneConfig);
         }
         if (json.get(VLAN_INTF_NAME) != null) {
             nodeBuilder.vlanIntf(json.get(VLAN_INTF_NAME).asText());
@@ -205,30 +235,36 @@
         }
         nodeBuilder.controllers(controllers);
 
-        // parse authentication
-        JsonNode authJson = json.get(AUTHENTICATION);
-        if (authJson != null) {
+        // parse neutron config
+        JsonNode neutronConfigJson = json.get(NEUTRON_CONFIG);
+        if (neutronConfigJson != null) {
+            final JsonCodec<NeutronConfig> neutronConfigJsonCodec =
+                                context.codec(NeutronConfig.class);
 
-            final JsonCodec<OpenstackAuth> authCodec = context.codec(OpenstackAuth.class);
-
-            OpenstackAuth auth = authCodec.decode((ObjectNode) authJson.deepCopy(), context);
-            nodeBuilder.authentication(auth);
+            NeutronConfig neutronConfig =
+                    neutronConfigJsonCodec.decode((ObjectNode)
+                            neutronConfigJson.deepCopy(), context);
+            nodeBuilder.neutronConfig(neutronConfig);
         }
 
         // parse ssh authentication
         JsonNode sshAuthJson = json.get(SSH_AUTH);
         if (sshAuthJson != null) {
-            final JsonCodec<OpenstackSshAuth> sshAuthJsonCodec = context.codec(OpenstackSshAuth.class);
+            final JsonCodec<OpenstackSshAuth> sshAuthJsonCodec =
+                                context.codec(OpenstackSshAuth.class);
 
-            OpenstackSshAuth sshAuth = sshAuthJsonCodec.decode((ObjectNode) sshAuthJson.deepCopy(), context);
+            OpenstackSshAuth sshAuth = sshAuthJsonCodec.decode((ObjectNode)
+                            sshAuthJson.deepCopy(), context);
             nodeBuilder.sshAuthInfo(sshAuth);
         }
 
         JsonNode dpdkConfigJson = json.get(DPDK_CONFIG);
         if (dpdkConfigJson != null) {
-            final JsonCodec<DpdkConfig> dpdkConfigJsonCodec = context.codec(DpdkConfig.class);
+            final JsonCodec<DpdkConfig> dpdkConfigJsonCodec =
+                                context.codec(DpdkConfig.class);
 
-            DpdkConfig dpdkConfig = dpdkConfigJsonCodec.decode((ObjectNode) dpdkConfigJson.deepCopy(), context);
+            DpdkConfig dpdkConfig = dpdkConfigJsonCodec.decode((ObjectNode)
+                                dpdkConfigJson.deepCopy(), context);
             nodeBuilder.dpdkConfig(dpdkConfig);
         }