22
22
import org .apache .logging .log4j .LogManager ;
23
23
import org .apache .logging .log4j .Logger ;
24
24
import org .apache .logging .log4j .message .ParameterizedMessage ;
25
+ import org .elasticsearch .Build ;
25
26
import org .elasticsearch .Version ;
26
27
import org .elasticsearch .action .ActionListener ;
27
28
import org .elasticsearch .action .ActionListenerResponseHandler ;
34
35
import org .elasticsearch .common .io .stream .StreamOutput ;
35
36
import org .elasticsearch .common .io .stream .Writeable ;
36
37
import org .elasticsearch .common .lease .Releasable ;
38
+ import org .elasticsearch .common .logging .DeprecationLogger ;
37
39
import org .elasticsearch .common .logging .Loggers ;
38
40
import org .elasticsearch .common .regex .Regex ;
39
41
import org .elasticsearch .common .settings .ClusterSettings ;
68
70
import java .util .function .Predicate ;
69
71
import java .util .function .Supplier ;
70
72
71
- public class TransportService extends AbstractLifecycleComponent implements ReportingService <TransportInfo >, TransportMessageListener ,
72
- TransportConnectionListener {
73
+ public class TransportService extends AbstractLifecycleComponent
74
+ implements ReportingService <TransportInfo >, TransportMessageListener , TransportConnectionListener {
75
+
73
76
private static final Logger logger = LogManager .getLogger (TransportService .class );
74
77
78
+ private static final String PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS_KEY = "es.unsafely_permit_handshake_from_incompatible_builds" ;
79
+ private static final boolean PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS ;
80
+
81
+ static {
82
+ final String value = System .getProperty (PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS_KEY );
83
+ if (value == null ) {
84
+ PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS = false ;
85
+ } else if (Boolean .parseBoolean (value )) {
86
+ PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS = true ;
87
+ } else {
88
+ throw new IllegalArgumentException ("invalid value [" + value + "] for system property ["
89
+ + PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS_KEY + "]" );
90
+ }
91
+ }
92
+
93
+
75
94
public static final String DIRECT_RESPONSE_PROFILE = ".direct" ;
76
95
public static final String HANDSHAKE_ACTION_NAME = "internal:transport/handshake" ;
77
96
@@ -182,7 +201,14 @@ public TransportService(Settings settings, Transport transport, ThreadPool threa
182
201
false , false ,
183
202
HandshakeRequest ::new ,
184
203
(request , channel , task ) -> channel .sendResponse (
185
- new HandshakeResponse (localNode , clusterName , localNode .getVersion ())));
204
+ new HandshakeResponse (localNode .getVersion (), Build .CURRENT .hash (), localNode , clusterName )));
205
+
206
+ if (PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS ) {
207
+ logger .warn ("transport handshakes from incompatible builds are unsafely permitted on this node; remove system property [" +
208
+ PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS_KEY + "] to resolve this warning" );
209
+ DeprecationLogger .getLogger (TransportService .class ).deprecate ("permit_handshake_from_incompatible_builds" ,
210
+ "system property [" + PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS_KEY + "] is deprecated and should be removed" );
211
+ }
186
212
}
187
213
188
214
public RemoteClusterService getRemoteClusterService () {
@@ -440,8 +466,8 @@ public void onResponse(HandshakeResponse response) {
440
466
public void onFailure (Exception e ) {
441
467
listener .onFailure (e );
442
468
}
443
- }
444
- , HandshakeResponse ::new , ThreadPool .Names .GENERIC
469
+ },
470
+ HandshakeResponse ::new , ThreadPool .Names .GENERIC
445
471
));
446
472
}
447
473
@@ -463,28 +489,89 @@ private HandshakeRequest() {
463
489
}
464
490
465
491
public static class HandshakeResponse extends TransportResponse {
492
+
493
+ private static final Version BUILD_HASH_HANDSHAKE_VERSION = Version .V_8_0_0 ;
494
+
495
+ private final Version version ;
496
+
497
+ @ Nullable // if version < BUILD_HASH_HANDSHAKE_VERSION
498
+ private final String buildHash ;
499
+
466
500
private final DiscoveryNode discoveryNode ;
501
+
467
502
private final ClusterName clusterName ;
468
- private final Version version ;
469
503
470
- public HandshakeResponse (DiscoveryNode discoveryNode , ClusterName clusterName , Version version ) {
471
- this .discoveryNode = discoveryNode ;
472
- this .version = version ;
473
- this .clusterName = clusterName ;
504
+ public HandshakeResponse (Version version , String buildHash , DiscoveryNode discoveryNode , ClusterName clusterName ) {
505
+ this .buildHash = Objects .requireNonNull (buildHash );
506
+ this .discoveryNode = Objects .requireNonNull (discoveryNode );
507
+ this .version = Objects .requireNonNull (version );
508
+ this .clusterName = Objects .requireNonNull (clusterName );
474
509
}
475
510
476
511
public HandshakeResponse (StreamInput in ) throws IOException {
477
512
super (in );
478
- discoveryNode = in .readOptionalWriteable (DiscoveryNode ::new );
479
- clusterName = new ClusterName (in );
480
- version = Version .readVersion (in );
513
+ if (in .getVersion ().onOrAfter (BUILD_HASH_HANDSHAKE_VERSION )) {
514
+ // the first two fields need only VInts and raw (ASCII) characters, so we cross our fingers and hope that they appear
515
+ // on the wire as we expect them to even if this turns out to be an incompatible build
516
+ version = Version .readVersion (in );
517
+ buildHash = in .readString ();
518
+
519
+ try {
520
+ // If the remote node is incompatible then make an effort to identify it anyway, so we can mention it in the exception
521
+ // message, but recognise that this may fail
522
+ discoveryNode = new DiscoveryNode (in );
523
+ } catch (Exception e ) {
524
+ if (isIncompatibleBuild (version , buildHash )) {
525
+ throw new IllegalArgumentException ("unidentifiable remote node is build [" + buildHash +
526
+ "] of version [" + version + "] but this node is build [" + Build .CURRENT .hash () +
527
+ "] of version [" + Version .CURRENT + "] which has an incompatible wire format" , e );
528
+ } else {
529
+ throw e ;
530
+ }
531
+ }
532
+
533
+ if (isIncompatibleBuild (version , buildHash )) {
534
+ if (PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS ) {
535
+ logger .warn ("remote node [{}] is build [{}] of version [{}] but this node is build [{}] of version [{}] " +
536
+ "which may not be compatible; remove system property [{}] to resolve this warning" ,
537
+ discoveryNode , buildHash , version , Build .CURRENT .hash (), Version .CURRENT ,
538
+ PERMIT_HANDSHAKES_FROM_INCOMPATIBLE_BUILDS_KEY );
539
+ } else {
540
+ throw new IllegalArgumentException ("remote node [" + discoveryNode + "] is build [" + buildHash +
541
+ "] of version [" + version + "] but this node is build [" + Build .CURRENT .hash () +
542
+ "] of version [" + Version .CURRENT + "] which has an incompatible wire format" );
543
+ }
544
+ }
545
+
546
+ clusterName = new ClusterName (in );
547
+ } else {
548
+ discoveryNode = in .readOptionalWriteable (DiscoveryNode ::new );
549
+ clusterName = new ClusterName (in );
550
+ version = Version .readVersion (in );
551
+ buildHash = null ;
552
+ }
481
553
}
482
554
483
555
@ Override
484
556
public void writeTo (StreamOutput out ) throws IOException {
485
- out .writeOptionalWriteable (discoveryNode );
486
- clusterName .writeTo (out );
487
- Version .writeVersion (version , out );
557
+ if (out .getVersion ().onOrAfter (BUILD_HASH_HANDSHAKE_VERSION )) {
558
+ Version .writeVersion (version , out );
559
+ out .writeString (buildHash );
560
+ discoveryNode .writeTo (out );
561
+ clusterName .writeTo (out );
562
+ } else {
563
+ out .writeOptionalWriteable (discoveryNode );
564
+ clusterName .writeTo (out );
565
+ Version .writeVersion (version , out );
566
+ }
567
+ }
568
+
569
+ public Version getVersion () {
570
+ return version ;
571
+ }
572
+
573
+ public String getBuildHash () {
574
+ return buildHash ;
488
575
}
489
576
490
577
public DiscoveryNode getDiscoveryNode () {
@@ -494,6 +581,10 @@ public DiscoveryNode getDiscoveryNode() {
494
581
public ClusterName getClusterName () {
495
582
return clusterName ;
496
583
}
584
+
585
+ private static boolean isIncompatibleBuild (Version version , String buildHash ) {
586
+ return version == Version .CURRENT && Build .CURRENT .hash ().equals (buildHash ) == false ;
587
+ }
497
588
}
498
589
499
590
public void disconnectFromNode (DiscoveryNode node ) {
@@ -1293,4 +1384,5 @@ public void onResponseReceived(long requestId, Transport.ResponseContext holder)
1293
1384
}
1294
1385
}
1295
1386
}
1387
+
1296
1388
}
0 commit comments