1
1
package org .opensearch .migrations .bulkload .common ;
2
2
3
-
4
3
import java .lang .reflect .InvocationTargetException ;
5
4
import java .util .HashSet ;
6
5
import java .util .Optional ;
9
8
import org .opensearch .migrations .UnboundVersionMatchers ;
10
9
import org .opensearch .migrations .Version ;
11
10
import org .opensearch .migrations .VersionMatchers ;
11
+ import org .opensearch .migrations .bulkload .common .http .CompressionMode ;
12
12
import org .opensearch .migrations .bulkload .common .http .ConnectionContext ;
13
13
import org .opensearch .migrations .bulkload .common .http .HttpResponse ;
14
14
import org .opensearch .migrations .bulkload .version_es_5_6 .OpenSearchClient_ES_5_6 ;
27
27
public class OpenSearchClientFactory {
28
28
private static final ObjectMapper objectMapper = new ObjectMapper ();
29
29
30
- private ConnectionContext connectionContext ;
30
+ private final ConnectionContext connectionContext ;
31
31
private Version version ;
32
+ private CompressionMode compressionMode ;
32
33
RestClient client ;
33
-
34
+
34
35
public OpenSearchClientFactory (ConnectionContext connectionContext ) {
35
36
if (connectionContext == null ) {
36
37
throw new IllegalArgumentException ("Connection context was not provided in constructor." );
@@ -40,26 +41,27 @@ public OpenSearchClientFactory(ConnectionContext connectionContext) {
40
41
}
41
42
42
43
public OpenSearchClient determineVersionAndCreate () {
43
- if (version == null ) {
44
- version = getClusterVersion ();
45
- }
46
- var clientClass = getOpenSearchClientClass (version );
47
- try {
48
- return clientClass .getConstructor (ConnectionContext .class , Version .class )
49
- .newInstance (connectionContext , version );
50
- } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e ) {
51
- throw new ClientInstantiationException ("Failed to instantiate OpenSearchClient" , e );
52
- }
44
+ return determineVersionAndCreate (null , null );
53
45
}
54
46
55
47
public OpenSearchClient determineVersionAndCreate (RestClient restClient , FailedRequestsLogger failedRequestsLogger ) {
56
48
if (version == null ) {
57
49
version = getClusterVersion ();
58
50
}
51
+
52
+ if (!connectionContext .isDisableCompression () && Boolean .TRUE .equals (getCompressionEnabled ())) {
53
+ compressionMode = CompressionMode .GZIP_BODY_COMPRESSION ;
54
+ } else {
55
+ compressionMode = CompressionMode .UNCOMPRESSED ;
56
+ }
59
57
var clientClass = getOpenSearchClientClass (version );
60
58
try {
61
- return clientClass .getConstructor (RestClient .class , FailedRequestsLogger .class , Version .class )
62
- .newInstance (restClient , failedRequestsLogger , version );
59
+ if (restClient == null && failedRequestsLogger == null ) {
60
+ return clientClass .getConstructor (ConnectionContext .class , Version .class , CompressionMode .class )
61
+ .newInstance (connectionContext , version , compressionMode );
62
+ }
63
+ return clientClass .getConstructor (RestClient .class , FailedRequestsLogger .class , Version .class , CompressionMode .class )
64
+ .newInstance (restClient , failedRequestsLogger , version , compressionMode );
63
65
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e ) {
64
66
throw new ClientInstantiationException ("Failed to instantiate OpenSearchClient" , e );
65
67
}
@@ -76,28 +78,47 @@ private Class<? extends OpenSearchClient> getOpenSearchClientClass(Version versi
76
78
throw new IllegalArgumentException ("Unsupported version: " + version );
77
79
}
78
80
79
- /** Amazon OpenSearch Serverless cluster don't have a version number, but
80
- * it is closely aligned with the latest open-source OpenSearch 2.X */
81
+ /** Amazon OpenSearch Serverless clusters don't have a version number, but
82
+ * they are closely aligned with the latest open-source OpenSearch 2.X */
81
83
private static final Version AMAZON_SERVERLESS_VERSION = Version .builder ()
82
84
.flavor (Flavor .AMAZON_SERVERLESS_OPENSEARCH )
83
85
.major (2 )
84
86
.build ();
85
87
88
+ private Boolean getCompressionEnabled () {
89
+ log .atInfo ().setMessage ("Checking compression on cluster" ).log ();
90
+ return client .getAsync ("_cluster/settings?include_defaults=true" , null )
91
+ .flatMap (this ::checkCompressionFromResponse )
92
+ .doOnError (e -> log .atWarn ()
93
+ .setMessage ("Check cluster compression failed" )
94
+ .setCause (e )
95
+ .log ())
96
+ .retryWhen (OpenSearchClient .CHECK_IF_ITEM_EXISTS_RETRY_STRATEGY )
97
+ .onErrorReturn (false )
98
+ .doOnNext (hasCompressionEnabled -> log .atInfo ()
99
+ .setMessage ("After querying target, compression={}" )
100
+ .addArgument (hasCompressionEnabled ).log ())
101
+ .block ();
102
+ }
103
+
86
104
public Version getClusterVersion () {
87
105
var versionFromRootApi = client .getAsync ("" , null )
88
- .flatMap (resp -> {
89
- if (resp .statusCode == 200 ) {
90
- return versionFromResponse (resp );
91
- }
92
- // If the root API doesn't exist, the cluster is OpenSearch Serverless
93
- if (resp .statusCode == 404 ) {
94
- return Mono .just (AMAZON_SERVERLESS_VERSION );
95
- }
96
- return Mono .error (new OpenSearchClient .UnexpectedStatusCode (resp ));
97
- })
98
- .doOnError (e -> log .error (e .getMessage ()))
99
- .retryWhen (OpenSearchClient .CHECK_IF_ITEM_EXISTS_RETRY_STRATEGY )
100
- .block ();
106
+ .flatMap (resp -> {
107
+ if (resp .statusCode == 200 ) {
108
+ return versionFromResponse (resp );
109
+ }
110
+ // If the root API doesn't exist, the cluster is OpenSearch Serverless
111
+ if (resp .statusCode == 404 ) {
112
+ return Mono .just (AMAZON_SERVERLESS_VERSION );
113
+ }
114
+ return Mono .error (new OpenSearchClient .UnexpectedStatusCode (resp ));
115
+ })
116
+ .doOnError (e -> log .atWarn ()
117
+ .setMessage ("Check cluster version failed" )
118
+ .setCause (e )
119
+ .log ())
120
+ .retryWhen (OpenSearchClient .CHECK_IF_ITEM_EXISTS_RETRY_STRATEGY )
121
+ .block ();
101
122
102
123
// Compatibility mode is only enabled on OpenSearch clusters responding with the version of 7.10.2
103
124
if (!VersionMatchers .isES_7_10 .test (versionFromRootApi )) {
@@ -108,8 +129,9 @@ public Version getClusterVersion() {
108
129
.doOnError (e -> log .error (e .getMessage ()))
109
130
.retryWhen (OpenSearchClient .CHECK_IF_ITEM_EXISTS_RETRY_STRATEGY )
110
131
.flatMap (hasCompatibilityModeEnabled -> {
111
- log .atInfo ().setMessage ("Checking CompatibilityMode, was enabled? {}" ).addArgument (hasCompatibilityModeEnabled ).log ();
132
+ log .atInfo ().setMessage ("After querying target, compatibilityMode= {}" ).addArgument (hasCompatibilityModeEnabled ).log ();
112
133
if (Boolean .FALSE .equals (hasCompatibilityModeEnabled )) {
134
+ assert versionFromRootApi != null : "Expected version from root api to be set" ;
113
135
return Mono .just (versionFromRootApi );
114
136
}
115
137
return client .getAsync ("_nodes/_all/nodes,version?format=json" , null )
@@ -120,8 +142,9 @@ public Version getClusterVersion() {
120
142
.onErrorResume (e -> {
121
143
log .atWarn ()
122
144
.setCause (e )
123
- .setMessage ("Unable to CompatibilityMode or determine the version from a plugin, falling back to version {}" )
145
+ .setMessage ("Unable to determine CompatibilityMode or version from plugin, falling back to version {}" )
124
146
.addArgument (versionFromRootApi ).log ();
147
+ assert versionFromRootApi != null : "Expected version from root api to be set" ;
125
148
return Mono .just (versionFromRootApi );
126
149
})
127
150
.block ();
@@ -153,28 +176,64 @@ private Mono<Version> versionFromResponse(HttpResponse resp) {
153
176
}
154
177
155
178
Mono <Boolean > checkCompatibilityModeFromResponse (HttpResponse resp ) {
179
+ return checkBooleanSettingFromResponse (
180
+ resp ,
181
+ "compatibility" ,
182
+ "override_main_response_version" ,
183
+ "Unable to determine if the cluster is in compatibility mode" );
184
+ }
185
+
186
+ Mono <Boolean > checkCompressionFromResponse (HttpResponse resp ) {
187
+ return checkBooleanSettingFromResponse (
188
+ resp ,
189
+ "http_compression" ,
190
+ "enabled" ,
191
+ "Unable to determine if compression is supported" )
192
+ .or (checkBooleanSettingFromResponse (
193
+ resp ,
194
+ "http" ,
195
+ "compression" ,
196
+ "Unable to determine if compression is supported" )
197
+ );
198
+ }
199
+
200
+ private Mono <Boolean > checkBooleanSettingFromResponse (
201
+ HttpResponse resp ,
202
+ String primaryKey ,
203
+ String secondaryKey ,
204
+ String errorLogMessage ) {
205
+
156
206
if (resp .statusCode != 200 ) {
157
207
return Mono .error (new OpenSearchClient .UnexpectedStatusCode (resp ));
158
208
}
159
209
try {
160
210
var body = Optional .of (objectMapper .readTree (resp .body ));
161
- var persistentlyInCompatibilityMode = inCompatibilityMode (body .map (n -> n .get ("persistent" )));
162
- var transientlyInCompatibilityMode = inCompatibilityMode (body .map (n -> n .get ("transient" )));
163
- return Mono .just (persistentlyInCompatibilityMode || transientlyInCompatibilityMode );
211
+ var persistentEnabled = isSettingEnabled (body .map (n -> n .get ("persistent" )), primaryKey , secondaryKey );
212
+ var transientEnabled = isSettingEnabled (body .map (n -> n .get ("transient" )), primaryKey , secondaryKey );
213
+ var defaultsEnabled = isSettingEnabled (body .map (n -> n .get ("defaults" )), primaryKey , secondaryKey );
214
+ return Mono .just (persistentEnabled || transientEnabled || defaultsEnabled );
164
215
} catch (Exception e ) {
165
- log .error ("Unable to determine if the cluster is in compatibility mode" , e );
166
- return Mono .error (new OpenSearchClient .OperationFailed ("Unable to determine if the cluster is in compatibility mode from response: " + e .getMessage (), resp ));
216
+ log .error (errorLogMessage , e );
217
+ return Mono .error (new OpenSearchClient .OperationFailed (errorLogMessage + " from response: " + e .getMessage (), resp ));
167
218
}
168
219
}
169
220
170
- private boolean inCompatibilityMode (Optional <JsonNode > node ) {
221
+ private boolean isSettingEnabled (Optional <JsonNode > node , String primaryKey , String secondaryKey ) {
171
222
return node .filter (n -> !n .isNull ())
172
- .map (n -> n .get ("compatibility" ))
173
- .filter (n -> !n .isNull ())
174
- .map (n -> n .get ("override_main_response_version" ))
175
- .filter (n -> !n .isNull ())
176
- .map (n -> n .asBoolean ())
177
- .orElse (false );
223
+ .map (n -> n .get (primaryKey ))
224
+ .filter (n -> !n .isNull ())
225
+ .map (n -> n .get (secondaryKey ))
226
+ .filter (n -> !n .isNull ())
227
+ .map (n -> {
228
+ if (n .isBoolean ()) {
229
+ return n .asBoolean ();
230
+ } else if (n .isTextual ()) {
231
+ return Boolean .parseBoolean (n .asText ());
232
+ } else {
233
+ return false ;
234
+ }
235
+ })
236
+ .orElse (false );
178
237
}
179
238
180
239
private Mono <Version > getVersionFromNodes (HttpResponse resp ) {
@@ -215,5 +274,4 @@ public ClientInstantiationException(String message, Exception cause) {
215
274
super (message , cause );
216
275
}
217
276
}
218
-
219
277
}
0 commit comments