Support injecting novaMetadataIp and novaMetadataPort through cfg

Change-Id: Ida449424235b70a791e8ed1d423f021f6d6726f7
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackMetadataProxyHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackMetadataProxyHandler.java
index c7fc417..9f928cd 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackMetadataProxyHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackMetadataProxyHandler.java
@@ -393,6 +393,29 @@
         }
 
         /**
+         * Obtains the metadata path.
+         *
+         * @param uri metadata request URI
+         * @return full metadata path
+         */
+        private String getMetadataPath(String uri) {
+            OpenstackNode controller = osNodeService.completeNodes(CONTROLLER).
+                    stream().findFirst().orElse(null);
+            if (controller == null) {
+                return null;
+            }
+
+            String novaMetadataIpTmp = controller.neutronConfig().novaMetadataIp();
+            String novaMetadataIp = novaMetadataIpTmp != null
+                    ? novaMetadataIpTmp : controller.managementIp().toString();
+            Integer novaMetadataPortTmp = controller.neutronConfig().novaMetadataPort();
+            int novaMetadataPort = novaMetadataPortTmp != null
+                    ? novaMetadataPortTmp : METADATA_SERVER_PORT;
+
+            return HTTP_PREFIX + novaMetadataIp + COLON + novaMetadataPort + uri;
+        }
+
+        /**
          * Proxyies HTTP request.
          *
          * @param oldRequest    HTTP request
@@ -403,15 +426,7 @@
                                                        InstancePort instPort) {
 
             CloseableHttpClient client = HttpClientBuilder.create().build();
-            OpenstackNode controller = osNodeService.completeNodes(CONTROLLER).
-                    stream().findFirst().orElse(null);
-            if (controller == null) {
-                return null;
-            }
-
-            String path = oldRequest.getRequestLine().getUri();
-            String url = HTTP_PREFIX + controller.managementIp().toString() +
-                    COLON + METADATA_SERVER_PORT + path;
+            String url = getMetadataPath(oldRequest.getRequestLine().getUri());
 
             if (StringUtils.isEmpty(url)) {
                 log.warn("The metadata endpoint is not configured!");
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultNeutronConfig.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultNeutronConfig.java
index acb5a3d..0dc1eea 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultNeutronConfig.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultNeutronConfig.java
@@ -29,12 +29,19 @@
 
     private final boolean useMetadataProxy;
     private final String metadataProxySecret;
+    private final String novaMetadataIp;
+    private final Integer novaMetadataPort;
 
     private static final String NOT_NULL_MSG = "% cannot be null";
 
-    private DefaultNeutronConfig(boolean useMetadataProxy, String metadataProxySecret) {
+    private DefaultNeutronConfig(boolean useMetadataProxy,
+                                 String metadataProxySecret,
+                                 String novaMetadataIp,
+                                 Integer novaMetadataPort) {
         this.useMetadataProxy = useMetadataProxy;
         this.metadataProxySecret = metadataProxySecret;
+        this.novaMetadataIp = novaMetadataIp;
+        this.novaMetadataPort = novaMetadataPort;
     }
 
     @Override
@@ -48,6 +55,16 @@
     }
 
     @Override
+    public String novaMetadataIp() {
+        return novaMetadataIp;
+    }
+
+    @Override
+    public Integer novaMetadataPort() {
+        return novaMetadataPort;
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) {
             return true;
@@ -56,7 +73,9 @@
         if (o instanceof DefaultNeutronConfig) {
             DefaultNeutronConfig that = (DefaultNeutronConfig) o;
             return Objects.equals(useMetadataProxy, that.useMetadataProxy) &&
-                    Objects.equals(metadataProxySecret, that.metadataProxySecret);
+                    Objects.equals(metadataProxySecret, that.metadataProxySecret) &&
+                    Objects.equals(novaMetadataIp, that.novaMetadataIp) &&
+                    Objects.equals(novaMetadataPort, that.novaMetadataPort);
         }
         return false;
     }
@@ -64,7 +83,8 @@
     @Override
     public int hashCode() {
 
-        return Objects.hash(useMetadataProxy, metadataProxySecret);
+        return Objects.hash(useMetadataProxy, metadataProxySecret,
+                            novaMetadataIp, novaMetadataPort);
     }
 
     @Override
@@ -72,6 +92,8 @@
         return MoreObjects.toStringHelper(this)
                 .add("useMetadataProxy", useMetadataProxy)
                 .add("metadataProxySecret", metadataProxySecret)
+                .add("novaMetadataIp", novaMetadataIp)
+                .add("novaMetadataPort", novaMetadataPort)
                 .toString();
     }
 
@@ -91,6 +113,9 @@
 
         private boolean useMetadataProxy;
         private String metadataProxySecret;
+        private String novaMetadataIp;
+        private Integer novaMetadataPort;
+
 
         // private constructor not intended to use from external
         private Builder() {
@@ -101,7 +126,8 @@
             checkArgument(metadataProxySecret != null,
                                         NOT_NULL_MSG, "metadataProxySecret");
 
-            return new DefaultNeutronConfig(useMetadataProxy, metadataProxySecret);
+            return new DefaultNeutronConfig(useMetadataProxy, metadataProxySecret,
+                                            novaMetadataIp, novaMetadataPort);
         }
 
         @Override
@@ -115,5 +141,17 @@
             this.metadataProxySecret = metadataProxySecret;
             return this;
         }
+
+        @Override
+        public NeutronConfig.Builder novaMetadataIp(String novaMetadataIp) {
+            this.novaMetadataIp = novaMetadataIp;
+            return this;
+        }
+
+        @Override
+        public NeutronConfig.Builder novaMetadataPort(Integer novaMetadataPort) {
+            this.novaMetadataPort = novaMetadataPort;
+            return this;
+        }
     }
 }
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NeutronConfig.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NeutronConfig.java
index 86ea2a9..e5e9cd4 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NeutronConfig.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NeutronConfig.java
@@ -37,6 +37,20 @@
     String metadataProxySecret();
 
     /**
+     * Returns NOVA metadata IP address.
+     *
+     * @return NOVA metadata IP address
+     */
+    String novaMetadataIp();
+
+    /**
+     * Returns NOVA metadata port number.
+     *
+     * @return NOVA metadata port number
+     */
+    Integer novaMetadataPort();
+
+    /**
      * Builder of neutron config.
      */
     interface Builder {
@@ -63,5 +77,21 @@
          * @return neutron config builder
          */
         Builder metadataProxySecret(String metadataProxySecret);
+
+        /**
+         * Returns neutron config with supplied NOVA metadata IP address.
+         *
+         * @param novaMetadataIp NOVA metadata IP address
+         * @return neutron config builder
+         */
+        Builder novaMetadataIp(String novaMetadataIp);
+
+        /**
+         * Returns neutron config with supplied NOVA metadata port number.
+         *
+         * @param novaMetadataPort NOVA metadata port number
+         * @return neutron config builder
+         */
+        Builder novaMetadataPort(Integer novaMetadataPort);
     }
 }
diff --git a/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/DefaultNeutronConfigTest.java b/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/DefaultNeutronConfigTest.java
index 63c3833..49369b7 100644
--- a/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/DefaultNeutronConfigTest.java
+++ b/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/DefaultNeutronConfigTest.java
@@ -33,6 +33,12 @@
     private static final String METADATA_PROXY_SECRET_1 = "onos";
     private static final String METADATA_PROXY_SECRET_2 = "cord";
 
+    private static final String NOVA_METADATA_IP_1 = "10.10.10.1";
+    private static final String NOVA_METADATA_IP_2 = "20.20.20.2";
+
+    private static final Integer NOVA_METADATA_PORT_1 = 8775;
+    private static final Integer NOVA_METADATA_PORT_2 = 8776;
+
     private NeutronConfig config1;
     private NeutronConfig sameAsConfig1;
     private NeutronConfig config2;
@@ -53,16 +59,22 @@
         config1 = DefaultNeutronConfig.builder()
                         .useMetadataProxy(USE_METADATA_PROXY_1)
                         .metadataProxySecret(METADATA_PROXY_SECRET_1)
+                        .novaMetadataIp(NOVA_METADATA_IP_1)
+                        .novaMetadataPort(NOVA_METADATA_PORT_1)
                         .build();
 
         sameAsConfig1 = DefaultNeutronConfig.builder()
                         .useMetadataProxy(USE_METADATA_PROXY_1)
                         .metadataProxySecret(METADATA_PROXY_SECRET_1)
+                        .novaMetadataIp(NOVA_METADATA_IP_1)
+                        .novaMetadataPort(NOVA_METADATA_PORT_1)
                         .build();
 
         config2 = DefaultNeutronConfig.builder()
                         .useMetadataProxy(USE_METADATA_PROXY_2)
                         .metadataProxySecret(METADATA_PROXY_SECRET_2)
+                        .novaMetadataIp(NOVA_METADATA_IP_2)
+                        .novaMetadataPort(NOVA_METADATA_PORT_2)
                         .build();
     }
 
@@ -85,5 +97,7 @@
 
         assertEquals(config.useMetadataProxy(), USE_METADATA_PROXY_1);
         assertEquals(config.metadataProxySecret(), METADATA_PROXY_SECRET_1);
+        assertEquals(config.novaMetadataIp(), NOVA_METADATA_IP_1);
+        assertEquals(config.novaMetadataPort(), NOVA_METADATA_PORT_1);
     }
 }
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
index 5acf180..48ca3ac 100644
--- 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
@@ -16,11 +16,12 @@
 
 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.NeutronConfig;
 import org.onosproject.openstacknode.api.DefaultNeutronConfig;
+import org.onosproject.openstacknode.api.NeutronConfig;
 
 import static org.onlab.util.Tools.nullIsIllegal;
 
@@ -31,14 +32,26 @@
 
     private static final String USE_METADATA_PROXY = "useMetadataProxy";
     private static final String METADATA_PROXY_SECRET = "metadataProxySecret";
+    private static final String NOVA_METADATA_IP = "novaMetadataIp";
+    private static final String NOVA_METADATA_PORT = "novaMetadataPort";
 
-    private static final String MISSING_MESSAGE = " is required in OpenstackNode";
+    private static final String MISSING_MESSAGE = " is required in NeutronConfig";
 
     @Override
     public ObjectNode encode(NeutronConfig entity, CodecContext context) {
-        return context.mapper().createObjectNode()
-                .put(USE_METADATA_PROXY, entity.useMetadataProxy())
+        ObjectNode node = context.mapper().createObjectNode();
+        node.put(USE_METADATA_PROXY, entity.useMetadataProxy())
                 .put(METADATA_PROXY_SECRET, entity.metadataProxySecret());
+
+        if (entity.novaMetadataIp() != null) {
+            node.put(NOVA_METADATA_IP, entity.novaMetadataIp());
+        }
+
+        if (entity.novaMetadataPort() != null) {
+            node.put(NOVA_METADATA_PORT, entity.novaMetadataPort());
+        }
+
+        return node;
     }
 
     @Override
@@ -53,9 +66,22 @@
         String metadataProxySecret = nullIsIllegal(json.get(METADATA_PROXY_SECRET).asText(),
                 METADATA_PROXY_SECRET + MISSING_MESSAGE);
 
-        return DefaultNeutronConfig.builder()
+        NeutronConfig.Builder builder = DefaultNeutronConfig.builder()
                 .useMetadataProxy(useMetadataProxy)
-                .metadataProxySecret(metadataProxySecret)
-                .build();
+                .metadataProxySecret(metadataProxySecret);
+
+        JsonNode novaMetadataIp = json.get(NOVA_METADATA_IP);
+
+        if (novaMetadataIp != null) {
+            builder.novaMetadataIp(novaMetadataIp.asText());
+        }
+
+        JsonNode novaMetadataPort = json.get(NOVA_METADATA_PORT);
+
+        if (novaMetadataPort != null) {
+            builder.novaMetadataPort(novaMetadataPort.asInt());
+        }
+
+        return builder.build();
     }
 }
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
index 185c7b6..de06f6b 100644
--- 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
@@ -29,6 +29,8 @@
 
     private static final String USE_METADATA_PROXY = "useMetadataProxy";
     private static final String METADATA_PROXY_SECRET = "metadataProxySecret";
+    private static final String NOVA_METADATA_IP = "novaMetadataIp";
+    private static final String NOVA_METADATA_PORT = "novaMetadataPort";
 
     private NeutronConfigJsonMatcher(NeutronConfig neutronConfig) {
         this.neutronConfig = neutronConfig;
@@ -57,6 +59,26 @@
             }
         }
 
+        // check NOVA metadata IP
+        JsonNode jsonNovaMetadataIp = jsonNode.get(NOVA_METADATA_IP);
+        if (jsonNovaMetadataIp != null) {
+            String novaMetadataIp = neutronConfig.novaMetadataIp();
+            if (!jsonNovaMetadataIp.asText().equals(novaMetadataIp)) {
+                description.appendText("novaMetadataIp was " + jsonNovaMetadataIp);
+                return false;
+            }
+        }
+
+        // check NOVA metadata port
+        JsonNode jsonNovaMetadataPort = jsonNode.get(NOVA_METADATA_PORT);
+        if (jsonNovaMetadataPort != null) {
+            Integer novaMetadataPort = neutronConfig.novaMetadataPort();
+            if (jsonNovaMetadataPort.asInt() != novaMetadataPort) {
+                description.appendText("novaMetadataPort was " + jsonNovaMetadataIp);
+                return false;
+            }
+        }
+
         return true;
     }
 
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 d97e47e..3788d01 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
@@ -278,6 +278,8 @@
         NeutronConfig neutronConfig = DefaultNeutronConfig.builder()
                                             .useMetadataProxy(true)
                                             .metadataProxySecret("onos")
+                                            .novaMetadataIp("172.16.130.10")
+                                            .novaMetadataPort(8775)
                                             .build();
 
         OpenstackNode node = DefaultOpenstackNode.builder()
@@ -321,6 +323,8 @@
 
         assertThat(neutronConfig.useMetadataProxy(), is(true));
         assertThat(neutronConfig.metadataProxySecret(), is("onos"));
+        assertThat(neutronConfig.novaMetadataIp(), is("172.16.130.10"));
+        assertThat(neutronConfig.novaMetadataPort(), is(8775));
     }
 
     /**
diff --git a/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/codec/OpenstackControllerNode.json b/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/codec/OpenstackControllerNode.json
index 6da832d..f654c40 100644
--- a/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/codec/OpenstackControllerNode.json
+++ b/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/codec/OpenstackControllerNode.json
@@ -15,6 +15,8 @@
   },
   "neutronConfig": {
     "useMetadataProxy": true,
-    "metadataProxySecret": "onos"
+    "metadataProxySecret": "onos",
+    "novaMetadataIp": "172.16.130.10",
+    "novaMetadataPort": 8775
   }
 }
\ No newline at end of file
diff --git a/apps/openstacknode/network-cfg.json b/apps/openstacknode/network-cfg.json
index 19e3b22..b0f0660 100644
--- a/apps/openstacknode/network-cfg.json
+++ b/apps/openstacknode/network-cfg.json
@@ -95,7 +95,9 @@
       },
       "neutronConfig": {
         "useMetadataProxy": true,
-        "metadataProxySecret": "onos"
+        "metadataProxySecret": "nova",
+        "novaMetadataIp": "172.16.130.10",
+        "novaMetadataPort": 8775
       }
     },
     {