Add keystone and neutron config classes and codec with unit tests

Change-Id: Ia89f5be9bac88927a383d56d56413ba23e3e5eb3
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/KeystoneConfigJsonMatcher.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/KeystoneConfigJsonMatcher.java
new file mode 100644
index 0000000..1b99ae3
--- /dev/null
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/KeystoneConfigJsonMatcher.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.openstacknode.api.KeystoneConfig;
+import org.onosproject.openstacknode.api.OpenstackAuth;
+
+/**
+ * Hamcrest matcher for keystone config.
+ */
+public final class KeystoneConfigJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+    private final KeystoneConfig keystoneConfig;
+
+    private static final String ENDPOINT = "endpoint";
+    private static final String AUTHENTICATION = "authentication";
+
+    private KeystoneConfigJsonMatcher(KeystoneConfig keystoneConfig) {
+        this.keystoneConfig = keystoneConfig;
+    }
+
+    @Override
+    protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+        // check endpoint
+        JsonNode jsonEndpoint = jsonNode.get(ENDPOINT);
+        if (jsonEndpoint != null) {
+            String endpoint = keystoneConfig.endpoint();
+            if (!jsonEndpoint.asText().equals(endpoint)) {
+                description.appendText("endpoint was " + jsonEndpoint);
+                return false;
+            }
+        }
+
+        // check openstack auth
+        JsonNode jsonAuth = jsonNode.get(AUTHENTICATION);
+        if (jsonAuth != null) {
+            OpenstackAuth auth = keystoneConfig.authentication();
+            OpenstackAuthJsonMatcher authMatcher =
+                    OpenstackAuthJsonMatcher.matchOpenstackAuth(auth);
+            return authMatcher.matches(jsonAuth);
+        }
+
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText(keystoneConfig.toString());
+    }
+
+    /**
+     * Factory to allocate keystone config matcher.
+     *
+     * @param config keystone config object we are looking for
+     * @return matcher
+     */
+    public static KeystoneConfigJsonMatcher matchKeystoneConfig(KeystoneConfig config) {
+        return new KeystoneConfigJsonMatcher(config);
+    }
+}
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/NeutronConfigJsonMatcher.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/NeutronConfigJsonMatcher.java
new file mode 100644
index 0000000..185c7b6
--- /dev/null
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/NeutronConfigJsonMatcher.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.openstacknode.api.NeutronConfig;
+
+/**
+ * Hamcrest matcher for neutron config.
+ */
+public final class NeutronConfigJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+    private final NeutronConfig neutronConfig;
+
+    private static final String USE_METADATA_PROXY = "useMetadataProxy";
+    private static final String METADATA_PROXY_SECRET = "metadataProxySecret";
+
+    private NeutronConfigJsonMatcher(NeutronConfig neutronConfig) {
+        this.neutronConfig = neutronConfig;
+    }
+
+    @Override
+    protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+        // check useMetaDataProxy
+        JsonNode jsonUseMetadataProxy = jsonNode.get(USE_METADATA_PROXY);
+        if (jsonUseMetadataProxy != null) {
+            boolean useMetadataProxy = neutronConfig.useMetadataProxy();
+            if (jsonUseMetadataProxy.asBoolean() != useMetadataProxy) {
+                description.appendText("useMetadataProxy was " + jsonUseMetadataProxy);
+                return false;
+            }
+        }
+
+        // check metadataProxySecret
+        JsonNode jsonMetadataProxySecret = jsonNode.get(METADATA_PROXY_SECRET);
+        if (jsonMetadataProxySecret != null) {
+            String metadataProxySecret = neutronConfig.metadataProxySecret();
+            if (!jsonMetadataProxySecret.asText().equals(metadataProxySecret)) {
+                description.appendText("metadataProxySecret was " + jsonUseMetadataProxy);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText(neutronConfig.toString());
+    }
+
+    /**
+     * Factory to allocate neutron config matcher.
+     *
+     * @param config neutron config object we are looking for
+     * @return matcher
+     */
+    public static NeutronConfigJsonMatcher matchNeutronConfig(NeutronConfig config) {
+        return new NeutronConfigJsonMatcher(config);
+    }
+}
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeCodecTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeCodecTest.java
index af5fdf4..d97e47e 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeCodecTest.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeCodecTest.java
@@ -33,6 +33,8 @@
 import org.onosproject.openstacknode.api.DefaultOpenstackNode;
 import org.onosproject.openstacknode.api.DpdkConfig;
 import org.onosproject.openstacknode.api.DpdkInterface;
+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;
@@ -40,6 +42,8 @@
 import org.onosproject.openstacknode.api.OpenstackSshAuth;
 import org.onosproject.openstacknode.impl.DefaultDpdkConfig;
 import org.onosproject.openstacknode.impl.DefaultDpdkInterface;
+import org.onosproject.openstacknode.api.DefaultKeystoneConfig;
+import org.onosproject.openstacknode.api.DefaultNeutronConfig;
 import org.onosproject.openstacknode.impl.DefaultOpenstackPhyInterface;
 import org.onosproject.openstacknode.impl.DefaultOpenstackSshAuth;
 
@@ -65,6 +69,7 @@
  */
 public class OpenstackNodeCodecTest {
     MockCodecContext context;
+
     JsonCodec<OpenstackNode> openstackNodeCodec;
     JsonCodec<OpenstackPhyInterface> openstackPhyIntfJsonCodec;
     JsonCodec<ControllerInfo> openstackControllerJsonCodec;
@@ -72,6 +77,8 @@
     JsonCodec<OpenstackSshAuth> openstackSshAuthJsonCodec;
     JsonCodec<DpdkConfig> dpdkConfigJsonCodec;
     JsonCodec<DpdkInterface> dpdkInterfaceJsonCodec;
+    JsonCodec<KeystoneConfig> keystoneConfigJsonCodec;
+    JsonCodec<NeutronConfig> neutronConfigJsonCodec;
 
     final CoreService mockCoreService = createMock(CoreService.class);
     private static final String REST_APP_ID = "org.onosproject.rest";
@@ -86,6 +93,8 @@
         openstackSshAuthJsonCodec = new OpenstackSshAuthCodec();
         dpdkConfigJsonCodec = new DpdkConfigCodec();
         dpdkInterfaceJsonCodec = new DpdkInterfaceCodec();
+        keystoneConfigJsonCodec = new KeystoneConfigCodec();
+        neutronConfigJsonCodec = new NeutronConfigCodec();
 
         assertThat(openstackNodeCodec, notNullValue());
         assertThat(openstackPhyIntfJsonCodec, notNullValue());
@@ -94,6 +103,8 @@
         assertThat(openstackSshAuthJsonCodec, notNullValue());
         assertThat(dpdkConfigJsonCodec, notNullValue());
         assertThat(dpdkInterfaceJsonCodec, notNullValue());
+        assertThat(keystoneConfigJsonCodec, notNullValue());
+        assertThat(neutronConfigJsonCodec, notNullValue());
 
         expect(mockCoreService.registerApplication(REST_APP_ID))
                 .andReturn(APP_ID).anyTimes();
@@ -257,13 +268,25 @@
                 .perspective(OpenstackAuth.Perspective.PUBLIC)
                 .build();
 
+        String endpoint = "172.16.130.10:35357/v2.0";
+
+        KeystoneConfig keystoneConfig = DefaultKeystoneConfig.builder()
+                                            .endpoint(endpoint)
+                                            .authentication(auth)
+                                            .build();
+
+        NeutronConfig neutronConfig = DefaultNeutronConfig.builder()
+                                            .useMetadataProxy(true)
+                                            .metadataProxySecret("onos")
+                                            .build();
+
         OpenstackNode node = DefaultOpenstackNode.builder()
                 .hostname("controller")
                 .type(OpenstackNode.NodeType.CONTROLLER)
                 .state(NodeState.INIT)
                 .managementIp(IpAddress.valueOf("172.16.130.10"))
-                .endpoint("keystone-end-point-url")
-                .authentication(auth)
+                .keystoneConfig(keystoneConfig)
+                .neutronConfig(neutronConfig)
                 .build();
 
         ObjectNode nodeJson = openstackNodeCodec.encode(node, context);
@@ -280,9 +303,10 @@
         assertThat(node.hostname(), is("controller"));
         assertThat(node.type().name(), is("CONTROLLER"));
         assertThat(node.managementIp().toString(), is("172.16.130.10"));
-        assertThat(node.endpoint(), is("keystone-end-point-url"));
 
-        OpenstackAuth auth = node.authentication();
+        KeystoneConfig keystoneConfig = node.keystoneConfig();
+        OpenstackAuth auth = keystoneConfig.authentication();
+        String endpoint = keystoneConfig.endpoint();
 
         assertThat(auth.version(), is("v2.0"));
         assertThat(auth.protocol(), is(OpenstackAuth.Protocol.HTTP));
@@ -290,6 +314,38 @@
         assertThat(auth.password(), is("nova"));
         assertThat(auth.project(), is("admin"));
         assertThat(auth.perspective(), is(OpenstackAuth.Perspective.PUBLIC));
+
+        assertThat(endpoint, is("172.16.130.10:35357/v2.0"));
+
+        NeutronConfig neutronConfig = node.neutronConfig();
+
+        assertThat(neutronConfig.useMetadataProxy(), is(true));
+        assertThat(neutronConfig.metadataProxySecret(), is("onos"));
+    }
+
+    /**
+     * Tests the openstack obsolete controller node decoding.
+     */
+    @Test
+    public void testOpenstackObsoleteControllerNodeDecode() throws IOException {
+        OpenstackNode node = getOpenstackNode("OpenstackObsoleteControllerNode.json");
+
+        assertThat(node.hostname(), is("controller"));
+        assertThat(node.type().name(), is("CONTROLLER"));
+        assertThat(node.managementIp().toString(), is("172.16.130.10"));
+
+        KeystoneConfig keystoneConfig = node.keystoneConfig();
+        OpenstackAuth auth = keystoneConfig.authentication();
+        String endpoint = keystoneConfig.endpoint();
+
+        assertThat(auth.version(), is("v2.0"));
+        assertThat(auth.protocol(), is(OpenstackAuth.Protocol.HTTP));
+        assertThat(auth.username(), is("admin"));
+        assertThat(auth.password(), is("nova"));
+        assertThat(auth.project(), is("admin"));
+        assertThat(auth.perspective(), is(OpenstackAuth.Perspective.PUBLIC));
+
+        assertThat(endpoint, is("172.16.130.10:35357/v2.0"));
     }
 
     /**
@@ -349,6 +405,12 @@
             if (entityClass == DpdkInterface.class) {
                 return (JsonCodec<T>) dpdkInterfaceJsonCodec;
             }
+            if (entityClass == KeystoneConfig.class) {
+                return (JsonCodec<T>) keystoneConfigJsonCodec;
+            }
+            if (entityClass == NeutronConfig.class) {
+                return (JsonCodec<T>) neutronConfigJsonCodec;
+            }
             return manager.getCodec(entityClass);
         }
 
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeJsonMatcher.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeJsonMatcher.java
index 6e3b473..5a94649 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeJsonMatcher.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/codec/OpenstackNodeJsonMatcher.java
@@ -21,7 +21,6 @@
 import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.openstacknode.api.Constants;
 import org.onosproject.openstacknode.api.DpdkConfig;
-import org.onosproject.openstacknode.api.OpenstackAuth;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackPhyInterface;
 import org.onosproject.openstacknode.api.OpenstackSshAuth;
@@ -113,17 +112,6 @@
             }
         }
 
-        // check openstack auth
-        JsonNode jsonAuth = jsonNode.get(AUTHENTICATION);
-        if (jsonAuth != null) {
-            OpenstackAuth auth = node.authentication();
-            OpenstackAuthJsonMatcher authMatcher =
-                    OpenstackAuthJsonMatcher.matchOpenstackAuth(auth);
-            if (!authMatcher.matches(jsonAuth)) {
-                return false;
-            }
-        }
-
         // check openstack ssh auth
         JsonNode jsonSshAuth = jsonNode.get(SSH_AUTH);
         if (jsonSshAuth != null) {
@@ -142,16 +130,6 @@
 
         }
 
-        // check endpoint URL
-        JsonNode jsonEndpoint = jsonNode.get(END_POINT);
-        if (jsonEndpoint != null) {
-            String endpoint = node.endpoint();
-            if (!jsonEndpoint.asText().equals(endpoint)) {
-                description.appendText("endpoint URL was " + jsonEndpoint);
-                return false;
-            }
-        }
-
         // check physical interfaces
         JsonNode jsonPhyIntfs = jsonNode.get(PHYSICAL_INTERFACES);
         if (jsonPhyIntfs != null) {