Skip to content

Commit 4cb0a06

Browse files
Merge branch 'main' into sql/cli_cps
2 parents 9ca1ca6 + 88ea038 commit 4cb0a06

File tree

63 files changed

+5694
-87
lines changed

Some content is hidden

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

63 files changed

+5694
-87
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal.info
11+
12+
import org.elasticsearch.gradle.fixtures.AbstractGradleFuncTest
13+
import org.gradle.testkit.runner.TaskOutcome
14+
15+
class GlobalBuildInfoPluginOfflineBranchesFallbackFuncTest extends AbstractGradleFuncTest {
16+
17+
def setup() {
18+
// This plugin reads files from the workspace and performs environment detection
19+
// that is not compatible with the configuration cache in functional tests.
20+
configurationCacheCompatible = false
21+
}
22+
23+
def "offline mode falls back to local branches.json when present"() {
24+
given:
25+
writeBwcVersionSource()
26+
writeBranchesJson()
27+
writeBuildThatResolvesBwcVersions()
28+
29+
when:
30+
def result = gradleRunner(
31+
"resolveBwcVersions",
32+
"--offline",
33+
// Make any accidental outbound HTTPS attempt fail deterministically.
34+
"-Dhttps.proxyHost=127.0.0.1",
35+
"-Dhttps.proxyPort=1",
36+
"-Dhttp.proxyHost=127.0.0.1",
37+
"-Dhttp.proxyPort=1",
38+
"-DBWC_VERSION_SOURCE=${file("Version.java").absolutePath}"
39+
).build()
40+
41+
then:
42+
result.task(":resolveBwcVersions").outcome == TaskOutcome.SUCCESS
43+
assertOutputContains(
44+
result.output,
45+
"Gradle is running in offline mode; falling back to local branches.json"
46+
)
47+
assertOutputContains(result.output, "BWC_VERSIONS_RESOLVED")
48+
}
49+
50+
def "offline mode without local branches.json retains failure behavior"() {
51+
given:
52+
writeBwcVersionSource()
53+
// Intentionally do not create branches.json
54+
writeBuildThatResolvesBwcVersions()
55+
56+
when:
57+
def result = gradleRunner(
58+
"resolveBwcVersions",
59+
"--offline",
60+
"-Dhttps.proxyHost=127.0.0.1",
61+
"-Dhttps.proxyPort=1",
62+
"-Dhttp.proxyHost=127.0.0.1",
63+
"-Dhttp.proxyPort=1",
64+
"-DBWC_VERSION_SOURCE=${file("Version.java").absolutePath}"
65+
).buildAndFail()
66+
67+
then:
68+
assertOutputContains(result.output, "Failed to download branches.json from:")
69+
assertOutputMissing(result.output, "falling back to local branches.json")
70+
}
71+
72+
def "non-offline mode does not fall back to local branches.json"() {
73+
given:
74+
writeBwcVersionSource()
75+
writeBranchesJson()
76+
writeBuildThatResolvesBwcVersions()
77+
78+
when:
79+
def result = gradleRunner(
80+
"resolveBwcVersions",
81+
// Not passing --offline on purpose.
82+
"-Dhttps.proxyHost=127.0.0.1",
83+
"-Dhttps.proxyPort=1",
84+
"-Dhttp.proxyHost=127.0.0.1",
85+
"-Dhttp.proxyPort=1",
86+
"-DBWC_VERSION_SOURCE=${file("Version.java").absolutePath}"
87+
).buildAndFail()
88+
89+
then:
90+
assertOutputContains(result.output, "Failed to download branches.json from:")
91+
assertOutputMissing(result.output, "falling back to local branches.json")
92+
}
93+
94+
private void writeBuildThatResolvesBwcVersions() {
95+
buildFile.text = """
96+
plugins {
97+
id 'elasticsearch.global-build-info'
98+
}
99+
100+
tasks.register("resolveBwcVersions") {
101+
doLast {
102+
// Force bwcVersions resolution, which triggers branches.json loading.
103+
def bwcVersions = buildParams.bwcVersionsProvider.get()
104+
println "BWC_VERSIONS_RESOLVED=[" + bwcVersions + "]"
105+
}
106+
}
107+
"""
108+
}
109+
110+
private void writeBranchesJson() {
111+
file("branches.json").text = """\
112+
{
113+
"branches": [
114+
{ "branch": "main", "version": "9.1.0" },
115+
{ "branch": "9.0", "version": "9.0.0" }
116+
]
117+
}
118+
""".stripIndent()
119+
}
120+
121+
private void writeBwcVersionSource() {
122+
// This file is parsed via regex; version constants must have a non-word
123+
// character before `public` and must end with `);` to match the pattern.
124+
file("Version.java").text = """\
125+
package org.elasticsearch;
126+
127+
public class Version {
128+
// Only used by GlobalBuildInfoPlugin in tests via regex parsing.
129+
public static final Version V_9_0_0 = Version.fromId(9000000);
130+
public static final Version V_9_1_0 = Version.fromId(9010000);
131+
132+
private static Version fromId(int id) {
133+
return new Version();
134+
}
135+
}
136+
"""
137+
}
138+
}
139+

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,24 @@ private List<Version> parseVersionLines(List<String> versionLines) {
214214
}
215215

216216
private List<DevelopmentBranch> getDevelopmentBranches() {
217-
String branchesFileLocation = project.getProviders()
218-
.gradleProperty(BRANCHES_FILE_LOCATION_PROPERTY)
219-
.getOrElse(DEFAULT_BRANCHES_FILE_URL);
217+
Provider<String> branchesFileLocationProperty = project.getProviders().gradleProperty(BRANCHES_FILE_LOCATION_PROPERTY);
218+
boolean hasExplicitBranchesFileLocation = branchesFileLocationProperty.isPresent();
219+
String branchesFileLocation = hasExplicitBranchesFileLocation ? branchesFileLocationProperty.get() : DEFAULT_BRANCHES_FILE_URL;
220+
if (hasExplicitBranchesFileLocation == false
221+
&& project.getGradle().getStartParameter().isOffline()
222+
&& branchesFileLocation.startsWith("http")) {
223+
File localBranchesFile = new File(Util.locateElasticsearchWorkspace(project.getGradle()), "branches.json");
224+
if (localBranchesFile.isFile()) {
225+
LOGGER.warn(
226+
"Gradle is running in offline mode; falling back to local branches.json at [{}] instead of downloading from [{}]. "
227+
+ "To override, set Gradle property [{}].",
228+
localBranchesFile.getAbsolutePath(),
229+
branchesFileLocation,
230+
BRANCHES_FILE_LOCATION_PROPERTY
231+
);
232+
branchesFileLocation = localBranchesFile.getAbsolutePath();
233+
}
234+
}
220235
LOGGER.info("Reading branches.json from {}", branchesFileLocation);
221236
byte[] branchesBytes;
222237
if (branchesFileLocation.startsWith("http")) {

build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/EmptyDirTaskTests.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
import java.io.File;
1717
import java.io.IOException;
18+
import java.nio.file.Files;
19+
import java.nio.file.attribute.PosixFilePermission;
20+
import java.util.Collections;
21+
import java.util.Set;
1822

1923
import static org.junit.Assert.assertEquals;
2024
import static org.junit.Assert.assertFalse;
@@ -61,9 +65,8 @@ public void testCreateEmptyDirNoPermissions() throws Exception {
6165

6266
assertTrue(newEmptyFolder.exists());
6367
assertTrue(newEmptyFolder.isDirectory());
64-
assertFalse(newEmptyFolder.canExecute());
65-
assertFalse(newEmptyFolder.canRead());
66-
assertFalse(newEmptyFolder.canWrite());
68+
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(newEmptyFolder.toPath());
69+
assertEquals(Collections.emptySet(), permissions);
6770

6871
// cleanup
6972
newEmptyFolder.delete();

distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# Extract Elasticsearch artifact
2626
################################################################################
2727
28-
FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:efc70f02cdc8aaa7eb5196c5d17719098a3f4bba347aa966a85f7e5452d0a0ca AS builder
28+
FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:e4cb92038b58c8c881962a17ec0b9970857a801c0a52f75550258f92f1e93ca1 AS builder
2929
3030
# Install required packages to extract the Elasticsearch distribution
3131
RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -104,7 +104,7 @@ WORKDIR /usr/share/elasticsearch/config
104104
# Add entrypoint
105105
################################################################################
106106

107-
FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:efc70f02cdc8aaa7eb5196c5d17719098a3f4bba347aa966a85f7e5452d0a0ca
107+
FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:e4cb92038b58c8c881962a17ec0b9970857a801c0a52f75550258f92f1e93ca1
108108

109109
RUN <%= retry.loop(package_manager,
110110
"export DEBIAN_FRONTEND=noninteractive && \n" +

distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# Extract Elasticsearch artifact
2626
################################################################################
2727
28-
FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:4a82c706003370964df94913adfc47aab9a55b4fb2490260e7f7ebcf27cc4240 AS builder
28+
FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:568df5fb0e237c3a2139399d4bd8e80994f24321fa8469aec565b8566704e83a AS builder
2929
3030
# Install required packages to extract the Elasticsearch distribution
3131
RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -80,7 +80,7 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
8080
# Add entrypoint
8181
################################################################################
8282

83-
FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:4a82c706003370964df94913adfc47aab9a55b4fb2490260e7f7ebcf27cc4240
83+
FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:568df5fb0e237c3a2139399d4bd8e80994f24321fa8469aec565b8566704e83a
8484

8585
RUN <%= retry.loop(package_manager,
8686
"export DEBIAN_FRONTEND=noninteractive && \n" +

docs/changelog/142021.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
area: SQL
2+
issues: []
3+
pr: 142021
4+
summary: Add support for API key to JDBC and CLI
5+
type: enhancement

docs/changelog/142900.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
area: ES|QL
2+
issues: []
3+
pr: 142900
4+
summary: Add support for ORC file format
5+
type: feature

docs/reference/query-languages/sql/sql-cli.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ If security is enabled on your cluster, you can pass the username and password i
2828
$ ./bin/elasticsearch-sql-cli https://sql_user:strongpassword@some.server:9200
2929
```
3030

31+
### API Key Authentication [sql-cli-apikey]
32+
33+
As an alternative to basic authentication, you can use API key authentication with the `--apikey` option. API keys can be created using the [Create API key API](docs-content://deploy-manage/api-keys/elasticsearch-api-keys.md). The API key should be provided in its encoded form (the `encoded` value returned by the Create API key API):
34+
35+
```bash
36+
$ ./bin/elasticsearch-sql-cli --apikey <encoded-api-key> https://some.server:9200
37+
```
38+
39+
::::{note}
40+
When using API key authentication, do not include username and password in the URL. The CLI will return an error if both API key and basic authentication credentials are provided.
41+
::::
42+
43+
::::{warning}
44+
Command line arguments are visible to other users on the system through process listing commands like `ps aux` or by inspecting `/proc/<pid>/cmdline`. Avoid using this method on shared systems where other users might be able to view your credentials.
45+
::::
46+
3147
Once the CLI is running you can use any [query](elasticsearch://reference/query-languages/sql/sql-spec.md) that Elasticsearch supports:
3248

3349
```sql

docs/reference/query-languages/sql/sql-jdbc.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,24 @@ $$$jdbc-cfg-timezone$$$
120120
: Basic Authentication password
121121

122122

123+
### API Key Authentication [jdbc-cfg-auth-apikey]
124+
125+
As an alternative to basic authentication, you can use API key authentication. API keys can be created using the [Create API key API](docs-content://deploy-manage/api-keys/elasticsearch-api-keys.md). The API key should be provided in its encoded form (the `encoded` value returned by the Create API key API).
126+
127+
`apiKey`
128+
: Encoded API key for authentication. Cannot be used together with `user`/`password` basic authentication.
129+
130+
::::{note}
131+
When using API key authentication, do not specify `user` or `password`. The driver will return an error if both API key and basic authentication credentials are provided.
132+
::::
133+
134+
Example connection URL using API key:
135+
136+
```text
137+
jdbc:es://http://server:9200/?apiKey=<encoded-api-key>
138+
```
139+
140+
123141
### SSL [jdbc-cfg-ssl]
124142

125143
`ssl` (default `false`)

docs/reference/query-languages/sql/sql-security.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ In case of an encrypted transport, the SSL/TLS support needs to be enabled in El
2020

2121
## Authentication [_authentication]
2222

23-
The authentication support in {{es}} SQL is of two types:
23+
The authentication support in {{es}} SQL is of three types:
2424

2525
Username/Password
2626
: Set these through `user` and `password` properties.
2727

28+
API Key
29+
: Use an API key for authentication by setting the `apiKey` property. API keys can be created using the [Create API key API](docs-content://deploy-manage/api-keys/elasticsearch-api-keys.md). The API key should be provided in its encoded form (the `encoded` value returned by the Create API key API). This is an alternative to username/password authentication and cannot be used together with it. For the CLI, use the `--apikey` command line option.
30+
2831
PKI/X.509
2932
: Use X.509 certificates to authenticate {{es}} SQL to {{es}}. For this, one would need to setup the `keystore` containing the private key and certificate to the appropriate user (configured in {{es}}) and the `truststore` with the CA certificate used to sign the SSL/TLS certificates in the {{es}} cluster. That is, one should setup the key to authenticate {{es}} SQL and also to verify that is the right one. To do so, one should set the `ssl.keystore.location` and `ssl.truststore.location` properties to indicate the `keystore` and `truststore` to use. It is recommended to have these secured through a password in which case `ssl.keystore.pass` and `ssl.truststore.pass` properties are required.
3033

0 commit comments

Comments
 (0)