Skip to content

Commit a8f413a

Browse files
authored
SQL: transfer version compatibility decision to the server (#53082)
This commit adds a new request object field, "version", containing the version of the requesting client. This parameter is now accepted - and for certain clients required - by the server and the request is validated against it. Currently server's and client's versions still need to be equal in order for the request to be accepted. Relaxing this check is going to be part of future work. On the clients' side, the only check remaining is to ensure that the peer server is supporting version backwards compatibility (i.e. is on, or newer than a certain release).
1 parent c0c53b8 commit a8f413a

File tree

45 files changed

+534
-235
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+534
-235
lines changed

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsDataSource.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
*/
66
package org.elasticsearch.xpack.sql.jdbc;
77

8+
import org.elasticsearch.xpack.sql.client.ClientVersion;
89
import org.elasticsearch.xpack.sql.client.ConnectionConfiguration;
9-
import org.elasticsearch.xpack.sql.client.Version;
1010

11+
import javax.sql.DataSource;
1112
import java.io.PrintWriter;
1213
import java.sql.Connection;
1314
import java.sql.SQLException;
@@ -16,16 +17,14 @@
1617
import java.util.Properties;
1718
import java.util.logging.Logger;
1819

19-
import javax.sql.DataSource;
20-
2120
/**
2221
* Factory for connections to Elasticsearch SQL.
2322
*/
2423
public class EsDataSource implements DataSource, Wrapper {
2524

2625
static {
2726
// invoke Version to perform classpath/jar sanity checks
28-
Version.CURRENT.toString();
27+
ClientVersion.CURRENT.toString();
2928
}
3029

3130
private String url;

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsDriver.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
package org.elasticsearch.xpack.sql.jdbc;
77

8-
import org.elasticsearch.xpack.sql.client.Version;
8+
import org.elasticsearch.xpack.sql.client.ClientVersion;
99

1010
import java.io.PrintWriter;
1111
import java.sql.Connection;
@@ -23,7 +23,7 @@ public class EsDriver implements Driver {
2323

2424
static {
2525
// invoke Version to perform classpath/jar sanity checks
26-
Version.CURRENT.toString();
26+
ClientVersion.CURRENT.toString();
2727

2828
try {
2929
register();
@@ -96,12 +96,12 @@ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws
9696

9797
@Override
9898
public int getMajorVersion() {
99-
return Version.CURRENT.major;
99+
return ClientVersion.CURRENT.major;
100100
}
101101

102102
@Override
103103
public int getMinorVersion() {
104-
return Version.CURRENT.minor;
104+
return ClientVersion.CURRENT.minor;
105105
}
106106

107107
@Override

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/InfoResponse.java

+7-12
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,23 @@
55
*/
66
package org.elasticsearch.xpack.sql.jdbc;
77

8+
9+
import org.elasticsearch.xpack.sql.proto.SqlVersion;
10+
811
/**
912
* General information about the server.
1013
*/
1114
class InfoResponse {
1215
final String cluster;
13-
final int majorVersion;
14-
final int minorVersion;
15-
final int revisionVersion;
16+
final SqlVersion version;
1617

17-
InfoResponse(String clusterName, byte versionMajor, byte versionMinor, byte revisionVersion) {
18+
InfoResponse(String clusterName, SqlVersion version) {
1819
this.cluster = clusterName;
19-
this.majorVersion = versionMajor;
20-
this.minorVersion = versionMinor;
21-
this.revisionVersion = revisionVersion;
20+
this.version = version;
2221
}
2322

2423
@Override
2524
public String toString() {
26-
return cluster + "[" + versionString() + "]";
27-
}
28-
29-
public String versionString() {
30-
return majorVersion + "." + minorVersion + "." + revisionVersion;
25+
return cluster + "[" + version.toString() + "]";
3126
}
3227
}

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
*/
66
package org.elasticsearch.xpack.sql.jdbc;
77

8+
import org.elasticsearch.xpack.sql.client.ClientVersion;
89
import org.elasticsearch.xpack.sql.client.ConnectionConfiguration;
910
import org.elasticsearch.xpack.sql.client.StringUtils;
10-
import org.elasticsearch.xpack.sql.client.Version;
1111

1212
import java.net.URI;
1313
import java.sql.DriverPropertyInfo;
@@ -70,7 +70,7 @@ public class JdbcConfiguration extends ConnectionConfiguration {
7070
// typically this should have already happened but in case the
7171
// EsDriver/EsDataSource are not used and the impl. classes used directly
7272
// this covers that case
73-
Version.CURRENT.toString();
73+
ClientVersion.CURRENT.toString();
7474
}
7575

7676
// immutable properties

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcConnection.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,10 @@ String getUserName() {
426426
// in fact, this information is cached by the underlying client
427427
// once retrieved
428428
int esInfoMajorVersion() throws SQLException {
429-
return client.serverInfo().majorVersion;
429+
return client.serverInfo().version.major;
430430
}
431431

432432
int esInfoMinorVersion() throws SQLException {
433-
return client.serverInfo().minorVersion;
433+
return client.serverInfo().version.minor;
434434
}
435435
}

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
*/
66
package org.elasticsearch.xpack.sql.jdbc;
77

8+
import org.elasticsearch.xpack.sql.client.ClientVersion;
89
import org.elasticsearch.xpack.sql.client.ObjectUtils;
9-
import org.elasticsearch.xpack.sql.client.Version;
1010

1111
import java.sql.Connection;
1212
import java.sql.DatabaseMetaData;
@@ -94,7 +94,7 @@ public String getDatabaseProductName() throws SQLException {
9494

9595
@Override
9696
public String getDatabaseProductVersion() throws SQLException {
97-
return Version.CURRENT.toString();
97+
return ClientVersion.CURRENT.toString();
9898
}
9999

100100
@Override
@@ -104,17 +104,17 @@ public String getDriverName() throws SQLException {
104104

105105
@Override
106106
public String getDriverVersion() throws SQLException {
107-
return Version.CURRENT.major + "." + Version.CURRENT.minor;
107+
return ClientVersion.CURRENT.major + "." + ClientVersion.CURRENT.minor;
108108
}
109109

110110
@Override
111111
public int getDriverMajorVersion() {
112-
return Version.CURRENT.major;
112+
return ClientVersion.CURRENT.major;
113113
}
114114

115115
@Override
116116
public int getDriverMinorVersion() {
117-
return Version.CURRENT.minor;
117+
return ClientVersion.CURRENT.minor;
118118
}
119119

120120
@Override
@@ -1111,12 +1111,12 @@ public int getDatabaseMinorVersion() throws SQLException {
11111111

11121112
@Override
11131113
public int getJDBCMajorVersion() throws SQLException {
1114-
return Version.jdbcMajorVersion();
1114+
return ClientVersion.jdbcMajorVersion();
11151115
}
11161116

11171117
@Override
11181118
public int getJDBCMinorVersion() throws SQLException {
1119-
return Version.jdbcMinorVersion();
1119+
return ClientVersion.jdbcMinorVersion();
11201120
}
11211121

11221122
@Override

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcHttpClient.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77

88
import org.elasticsearch.common.collect.Tuple;
99
import org.elasticsearch.common.unit.TimeValue;
10+
import org.elasticsearch.xpack.sql.client.ClientVersion;
1011
import org.elasticsearch.xpack.sql.client.HttpClient;
11-
import org.elasticsearch.xpack.sql.client.Version;
1212
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
1313
import org.elasticsearch.xpack.sql.proto.MainResponse;
1414
import org.elasticsearch.xpack.sql.proto.Mode;
1515
import org.elasticsearch.xpack.sql.proto.RequestInfo;
1616
import org.elasticsearch.xpack.sql.proto.SqlQueryRequest;
1717
import org.elasticsearch.xpack.sql.proto.SqlQueryResponse;
1818
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
19+
import org.elasticsearch.xpack.sql.proto.SqlVersion;
1920

2021
import java.sql.SQLException;
2122
import java.util.ArrayList;
@@ -62,7 +63,7 @@ Cursor query(String sql, List<SqlTypedParamValue> params, RequestMeta meta) thro
6263
null,
6364
Boolean.FALSE,
6465
null,
65-
new RequestInfo(Mode.JDBC),
66+
new RequestInfo(Mode.JDBC, ClientVersion.CURRENT),
6667
conCfg.fieldMultiValueLeniency(),
6768
conCfg.indexIncludeFrozen(),
6869
conCfg.binaryCommunication());
@@ -94,16 +95,15 @@ InfoResponse serverInfo() throws SQLException {
9495

9596
private InfoResponse fetchServerInfo() throws SQLException {
9697
MainResponse mainResponse = httpClient.serverInfo();
97-
Version version = Version.fromString(mainResponse.getVersion());
98-
return new InfoResponse(mainResponse.getClusterName(), version.major, version.minor, version.revision);
98+
SqlVersion version = SqlVersion.fromString(mainResponse.getVersion());
99+
return new InfoResponse(mainResponse.getClusterName(), version);
99100
}
100-
101+
101102
private void checkServerVersion() throws SQLException {
102-
if (serverInfo.majorVersion != Version.CURRENT.major
103-
|| serverInfo.minorVersion != Version.CURRENT.minor
104-
|| serverInfo.revisionVersion != Version.CURRENT.revision) {
103+
if (ClientVersion.isServerCompatible(serverInfo.version) == false) {
105104
throw new SQLException("This version of the JDBC driver is only compatible with Elasticsearch version " +
106-
Version.CURRENT.toString() + ", attempting to connect to a server version " + serverInfo.versionString());
105+
ClientVersion.CURRENT.majorMinorToString() + " or newer; attempting to connect to a server version " +
106+
serverInfo.version.toString());
107107
}
108108
}
109109

x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/VersionParityTests.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.elasticsearch.common.xcontent.XContentType;
1313
import org.elasticsearch.test.VersionUtils;
1414
import org.elasticsearch.test.http.MockResponse;
15+
import org.elasticsearch.xpack.sql.client.ClientVersion;
1516

1617
import java.io.IOException;
1718
import java.sql.SQLException;
@@ -31,9 +32,9 @@ public void testExceptionThrownOnIncompatibleVersions() throws IOException, SQLE
3132

3233
String url = JdbcConfiguration.URL_PREFIX + webServerAddress();
3334
SQLException ex = expectThrows(SQLException.class, () -> new JdbcHttpClient(JdbcConfiguration.create(url, null, 0)));
34-
assertEquals("This version of the JDBC driver is only compatible with Elasticsearch version "
35-
+ org.elasticsearch.xpack.sql.client.Version.CURRENT.toString()
36-
+ ", attempting to connect to a server version " + version.toString(), ex.getMessage());
35+
assertEquals("This version of the JDBC driver is only compatible with Elasticsearch version " +
36+
ClientVersion.CURRENT.majorMinorToString() + " or newer; attempting to connect to a server " +
37+
"version " + version.toString(), ex.getMessage());
3738
}
3839

3940
public void testNoExceptionThrownForCompatibleVersions() throws IOException {

x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/VersionTests.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66
package org.elasticsearch.xpack.sql.jdbc;
77

88
import org.elasticsearch.test.ESTestCase;
9-
import org.elasticsearch.xpack.sql.client.Version;
9+
import org.elasticsearch.xpack.sql.client.ClientVersion;
1010

1111
public class VersionTests extends ESTestCase {
1212
public void testVersionIsCurrent() {
1313
/* This test will only work properly in gradle because in gradle we run the tests
1414
* using the jar. */
15-
assertNotNull(Version.CURRENT.hash);
16-
assertEquals(org.elasticsearch.Version.CURRENT.major, Version.CURRENT.major);
17-
assertEquals(org.elasticsearch.Version.CURRENT.minor, Version.CURRENT.minor);
18-
assertEquals(org.elasticsearch.Version.CURRENT.revision, Version.CURRENT.revision);
15+
assertEquals(org.elasticsearch.Version.CURRENT.major, ClientVersion.CURRENT.major);
16+
assertEquals(org.elasticsearch.Version.CURRENT.minor, ClientVersion.CURRENT.minor);
17+
assertEquals(org.elasticsearch.Version.CURRENT.revision, ClientVersion.CURRENT.revision);
1918
}
2019
}

x-pack/plugin/sql/qa/multi-node/src/test/java/org/elasticsearch/xpack/sql/qa/multi_node/RestSqlMultinodeIT.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.mode;
2727
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.randomMode;
2828
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.toMap;
29+
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.version;
2930
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.SQL_QUERY_REST_ENDPOINT;
3031
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.columnInfo;
3132

@@ -110,7 +111,7 @@ private void assertCount(RestClient client, int count) throws IOException {
110111
expected.put("rows", singletonList(singletonList(count)));
111112

112113
Request request = new Request("POST", SQL_QUERY_REST_ENDPOINT);
113-
request.setJsonEntity("{\"query\": \"SELECT COUNT(*) FROM test\"" + mode(mode) + "}");
114+
request.setJsonEntity("{\"query\": \"SELECT COUNT(*) FROM test\"" + mode(mode) + version(mode) + "}");
114115
Map<String, Object> actual = toMap(client.performRequest(request), mode);
115116

116117
if (false == expected.equals(actual)) {

x-pack/plugin/sql/qa/security/src/test/java/org/elasticsearch/xpack/sql/qa/security/RestSqlSecurityIT.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.mode;
3434
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.randomMode;
35+
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.version;
3536
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.SQL_QUERY_REST_ENDPOINT;
3637
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.columnInfo;
3738
import static org.hamcrest.Matchers.containsString;
@@ -70,10 +71,10 @@ public void expectMatchesAdmin(String adminSql, String user, String userSql) thr
7071
public void expectScrollMatchesAdmin(String adminSql, String user, String userSql) throws Exception {
7172
String mode = randomMode();
7273
Map<String, Object> adminResponse = runSql(null,
73-
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1" + mode(mode) + "}",
74+
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1" + mode(mode) + version(mode) + "}",
7475
ContentType.APPLICATION_JSON), mode);
7576
Map<String, Object> otherResponse = runSql(user,
76-
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1" + mode(mode) + "}",
77+
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1" + mode(mode) + version(mode) + "}",
7778
ContentType.APPLICATION_JSON), mode);
7879

7980
String adminCursor = (String) adminResponse.remove("cursor");
@@ -83,9 +84,11 @@ public void expectScrollMatchesAdmin(String adminSql, String user, String userSq
8384
assertResponse(adminResponse, otherResponse);
8485
while (true) {
8586
adminResponse = runSql(null,
86-
new StringEntity("{\"cursor\": \"" + adminCursor + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON), mode);
87+
new StringEntity("{\"cursor\": \"" + adminCursor + "\"" + mode(mode) + version(mode) + "}",
88+
ContentType.APPLICATION_JSON), mode);
8789
otherResponse = runSql(user,
88-
new StringEntity("{\"cursor\": \"" + otherCursor + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON), mode);
90+
new StringEntity("{\"cursor\": \"" + otherCursor + "\"" + mode(mode) + version(mode) + "}",
91+
ContentType.APPLICATION_JSON), mode);
8992
adminCursor = (String) adminResponse.remove("cursor");
9093
otherCursor = (String) otherResponse.remove("cursor");
9194
assertResponse(adminResponse, otherResponse);
@@ -180,7 +183,8 @@ public void checkNoMonitorMain(String user) throws Exception {
180183
}
181184

182185
private static Map<String, Object> runSql(@Nullable String asUser, String mode, String sql) throws IOException {
183-
return runSql(asUser, new StringEntity("{\"query\": \"" + sql + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON), mode);
186+
return runSql(asUser, new StringEntity("{\"query\": \"" + sql + "\"" + mode(mode) + version(mode) + "}",
187+
ContentType.APPLICATION_JSON), mode);
184188
}
185189

186190
private static Map<String, Object> runSql(@Nullable String asUser, HttpEntity entity, String mode) throws IOException {
@@ -230,18 +234,18 @@ protected AuditLogAsserter createAuditLogAsserter() {
230234
*/
231235
public void testHijackScrollFails() throws Exception {
232236
createUser("full_access", "rest_minimal");
237+
final String mode = randomMode();
233238

234-
String mode = randomMode();
235239
Map<String, Object> adminResponse = RestActions.runSql(null,
236-
new StringEntity("{\"query\": \"SELECT * FROM test\", \"fetch_size\": 1" + mode(mode) + "}",
240+
new StringEntity("{\"query\": \"SELECT * FROM test\", \"fetch_size\": 1" + mode(mode) + version(mode) + "}",
237241
ContentType.APPLICATION_JSON), mode);
238242

239243
String cursor = (String) adminResponse.remove("cursor");
240244
assertNotNull(cursor);
241245

242-
final String m = randomMode();
243246
ResponseException e = expectThrows(ResponseException.class, () -> RestActions.runSql("full_access",
244-
new StringEntity("{\"cursor\":\"" + cursor + "\"" + mode(m) + "}", ContentType.APPLICATION_JSON), m));
247+
new StringEntity("{\"cursor\":\"" + cursor + "\"" + mode(mode) + version(mode) + "}", ContentType.APPLICATION_JSON),
248+
mode));
245249
// TODO return a better error message for bad scrolls
246250
assertThat(e.getMessage(), containsString("No search context found for id"));
247251
assertEquals(404, e.getResponse().getStatusLine().getStatusCode());

x-pack/plugin/sql/qa/security/src/test/java/org/elasticsearch/xpack/sql/qa/security/UserFunctionIT.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.mode;
3434
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.randomMode;
3535
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.toMap;
36+
import static org.elasticsearch.xpack.sql.qa.rest.BaseRestSqlTestCase.version;
3637
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.SQL_QUERY_REST_ENDPOINT;
3738
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.columnInfo;
3839

@@ -177,7 +178,8 @@ private Map<String, Object> runSql(String asUser, String mode, String sql) throw
177178
options.addHeader("es-security-runas-user", asUser);
178179
request.setOptions(options);
179180
}
180-
request.setEntity(new StringEntity("{\"query\": \"" + sql + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON));
181+
request.setEntity(new StringEntity("{\"query\": \"" + sql + "\"" + mode(mode) + version(mode) + "}",
182+
ContentType.APPLICATION_JSON));
181183
return toMap(client().performRequest(request), mode);
182184
}
183185

0 commit comments

Comments
 (0)