Browse Source

NETWORKING: http.publish_host Should Contain CNAME (#32806)

* NETWORKING: http.publish_host Should Contain CNAME

* Closes #22029
Armin Braun 7 years ago
parent
commit
94cdf0ceba

+ 3 - 0
buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

@@ -831,6 +831,9 @@ class BuildPlugin implements Plugin<Project> {
             // TODO: remove this once ctx isn't added to update script params in 7.0
             systemProperty 'es.scripting.update.ctx_in_params', 'false'
 
+            //TODO: remove this once the cname is prepended to the address by default in 7.0
+            systemProperty 'es.http.cname_in_publish_address', 'true'
+
             // Set the system keystore/truststore password if we're running tests in a FIPS-140 JVM
             if (project.inFipsJvm) {
                 systemProperty 'javax.net.ssl.trustStorePassword', 'password'

+ 2 - 0
docs/build.gradle

@@ -57,6 +57,8 @@ integTestCluster {
   // TODO: remove this for 7.0, this exists to allow the doc examples in 6.x to continue using the defaults
   systemProperty 'es.scripting.use_java_time', 'false'
   systemProperty 'es.scripting.update.ctx_in_params', 'false'
+  //TODO: remove this once the cname is prepended to the address by default in 7.0
+  systemProperty 'es.http.cname_in_publish_address', 'true'
 }
 
 // remove when https://github.com/elastic/elasticsearch/issues/31305 is fixed

+ 1 - 0
modules/lang-painless/build.gradle

@@ -26,6 +26,7 @@ integTestCluster {
   module project.project(':modules:mapper-extras')
   systemProperty 'es.scripting.use_java_time', 'true'
   systemProperty 'es.scripting.update.ctx_in_params', 'false'
+  systemProperty 'es.http.cname_in_publish_address', 'true'
 }
 
 dependencies {

+ 39 - 8
server/src/main/java/org/elasticsearch/http/HttpInfo.java

@@ -19,35 +19,52 @@
 
 package org.elasticsearch.http;
 
+import org.apache.logging.log4j.LogManager;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.logging.DeprecationLogger;
+import org.elasticsearch.common.network.InetAddresses;
 import org.elasticsearch.common.transport.BoundTransportAddress;
+import org.elasticsearch.common.transport.TransportAddress;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.xcontent.ToXContentFragment;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 
 import java.io.IOException;
 
+import static org.elasticsearch.common.Booleans.parseBoolean;
+
 public class HttpInfo implements Writeable, ToXContentFragment {
 
+    private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(LogManager.getLogger(HttpInfo.class));
+
+    /** Whether to add hostname to publish host field when serializing. */
+    private static final boolean CNAME_IN_PUBLISH_HOST =
+        parseBoolean(System.getProperty("es.http.cname_in_publish_address"), false);
+
     private final BoundTransportAddress address;
     private final long maxContentLength;
+    private final boolean cnameInPublishHost;
 
     public HttpInfo(StreamInput in) throws IOException {
-        address = BoundTransportAddress.readBoundTransportAddress(in);
-        maxContentLength = in.readLong();
+        this(BoundTransportAddress.readBoundTransportAddress(in), in.readLong(), CNAME_IN_PUBLISH_HOST);
     }
 
-    @Override
-    public void writeTo(StreamOutput out) throws IOException {
-        address.writeTo(out);
-        out.writeLong(maxContentLength);
+    public HttpInfo(BoundTransportAddress address, long maxContentLength) {
+        this(address, maxContentLength, CNAME_IN_PUBLISH_HOST);
     }
 
-    public HttpInfo(BoundTransportAddress address, long maxContentLength) {
+    HttpInfo(BoundTransportAddress address, long maxContentLength, boolean cnameInPublishHost) {
         this.address = address;
         this.maxContentLength = maxContentLength;
+        this.cnameInPublishHost = cnameInPublishHost;
+    }
+
+    @Override
+    public void writeTo(StreamOutput out) throws IOException {
+        address.writeTo(out);
+        out.writeLong(maxContentLength);
     }
 
     static final class Fields {
@@ -62,7 +79,21 @@ public class HttpInfo implements Writeable, ToXContentFragment {
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject(Fields.HTTP);
         builder.array(Fields.BOUND_ADDRESS, (Object[]) address.boundAddresses());
-        builder.field(Fields.PUBLISH_ADDRESS, address.publishAddress().toString());
+        TransportAddress publishAddress = address.publishAddress();
+        String publishAddressString = publishAddress.toString();
+        String hostString = publishAddress.address().getHostString();
+        if (InetAddresses.isInetAddress(hostString) == false) {
+            if (cnameInPublishHost) {
+                publishAddressString = hostString + '/' + publishAddress.toString();
+            } else {
+                DEPRECATION_LOGGER.deprecated(
+                    "[http.publish_host] was printed as [ip:port] instead of [hostname/ip:port]. "
+                        + "This format is deprecated and will change to [hostname/ip:port] in a future version. "
+                        + "Use -Des.http.cname_in_publish_address=true to enforce non-deprecated formatting."
+                );
+            }
+        }
+        builder.field(Fields.PUBLISH_ADDRESS, publishAddressString);
         builder.humanReadableField(Fields.MAX_CONTENT_LENGTH_IN_BYTES, Fields.MAX_CONTENT_LENGTH, maxContentLength());
         builder.endObject();
         return builder;

+ 97 - 0
server/src/test/java/org/elasticsearch/http/HttpInfoTests.java

@@ -0,0 +1,97 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you 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.elasticsearch.http;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.Map;
+import org.elasticsearch.common.network.NetworkAddress;
+import org.elasticsearch.common.transport.BoundTransportAddress;
+import org.elasticsearch.common.transport.TransportAddress;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.test.ESTestCase;
+
+public class HttpInfoTests extends ESTestCase {
+
+    public void testCorrectlyDisplayPublishedCname() throws Exception {
+        InetAddress localhost = InetAddress.getByName("localhost");
+        int port = 9200;
+        assertPublishAddress(
+            new HttpInfo(
+                new BoundTransportAddress(
+                    new TransportAddress[]{new TransportAddress(localhost, port)},
+                    new TransportAddress(localhost, port)
+                ), 0L, true
+            ), "localhost/" + NetworkAddress.format(localhost) + ':' + port
+        );
+    }
+
+    public void hideCnameIfDeprecatedFormat() throws Exception {
+        InetAddress localhost = InetAddress.getByName("localhost");
+        int port = 9200;
+        assertPublishAddress(
+            new HttpInfo(
+                new BoundTransportAddress(
+                    new TransportAddress[]{new TransportAddress(localhost, port)},
+                    new TransportAddress(localhost, port)
+                ), 0L, false
+            ), NetworkAddress.format(localhost) + ':' + port
+        );
+    }
+
+    public void testCorrectDisplayPublishedIp() throws Exception {
+        InetAddress localhost = InetAddress.getByName(NetworkAddress.format(InetAddress.getByName("localhost")));
+        int port = 9200;
+        assertPublishAddress(
+            new HttpInfo(
+                new BoundTransportAddress(
+                    new TransportAddress[]{new TransportAddress(localhost, port)},
+                    new TransportAddress(localhost, port)
+                ), 0L, true
+            ), NetworkAddress.format(localhost) + ':' + port
+        );
+    }
+
+    public void testCorrectDisplayPublishedIpv6() throws Exception {
+        int port = 9200;
+        TransportAddress localhost =
+            new TransportAddress(InetAddress.getByName(NetworkAddress.format(InetAddress.getByName("0:0:0:0:0:0:0:1"))), port);
+        assertPublishAddress(
+            new HttpInfo(
+                new BoundTransportAddress(new TransportAddress[]{localhost}, localhost), 0L, true
+            ), localhost.toString()
+        );
+    }
+
+    @SuppressWarnings("unchecked")
+    private void assertPublishAddress(HttpInfo httpInfo, String expected) throws IOException {
+        XContentBuilder builder = XContentFactory.jsonBuilder();
+        builder.startObject();
+        httpInfo.toXContent(builder, ToXContent.EMPTY_PARAMS);
+        builder.endObject();
+        assertEquals(
+            expected,
+            ((Map<String, Object>) createParser(builder).map().get(HttpInfo.Fields.HTTP))
+                .get(HttpInfo.Fields.PUBLISH_ADDRESS)
+        );
+    }
+}