Skip to content

Commit 6508617

Browse files
authored
Only Allow Enabling Streams If No Conflicting Indices Exist (#132064)
* New logic to check for conflicting indices before enabling streams plus tests * Update docs/changelog/132064.yaml * Fix tests * More YAML test fixes * Update changelog entry * Normalize to single quotes in gradle file and switch to enum for stream index prefix * Speed up index checking by pre-computing stream names and prefix and not using a stream * Fix race condition in YAML tests * Fix race condition in YAML tests - Take 2
1 parent 3adfae3 commit 6508617

File tree

6 files changed

+103
-9
lines changed

6 files changed

+103
-9
lines changed

docs/changelog/132064.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 132064
2+
summary: Only Allow Enabling Streams If No Conflicting Indices Exist
3+
area: Data streams
4+
type: enhancement
5+
issues: []

modules/streams/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ esplugin {
2020

2121
restResources {
2222
restApi {
23-
include '_common', 'streams', "bulk", "index", "ingest", "indices", "delete_by_query", "search"
23+
include '_common', 'streams', 'bulk', 'index', 'ingest', 'indices', 'delete_by_query', 'search'
2424
}
2525
}
2626

modules/streams/src/main/java/org/elasticsearch/rest/streams/logs/TransportLogsStreamsToggleActivation.java

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.apache.logging.log4j.LogManager;
1313
import org.apache.logging.log4j.Logger;
14+
import org.elasticsearch.ElasticsearchStatusException;
1415
import org.elasticsearch.action.ActionListener;
1516
import org.elasticsearch.action.support.ActionFilters;
1617
import org.elasticsearch.action.support.master.AcknowledgedRequest;
@@ -22,12 +23,15 @@
2223
import org.elasticsearch.cluster.block.ClusterBlockException;
2324
import org.elasticsearch.cluster.block.ClusterBlockLevel;
2425
import org.elasticsearch.cluster.metadata.ProjectId;
26+
import org.elasticsearch.cluster.metadata.ProjectMetadata;
2527
import org.elasticsearch.cluster.metadata.StreamsMetadata;
2628
import org.elasticsearch.cluster.project.ProjectResolver;
2729
import org.elasticsearch.cluster.service.ClusterService;
2830
import org.elasticsearch.cluster.service.MasterServiceTaskQueue;
2931
import org.elasticsearch.common.Priority;
32+
import org.elasticsearch.common.streams.StreamType;
3033
import org.elasticsearch.injection.guice.Inject;
34+
import org.elasticsearch.rest.RestStatus;
3135
import org.elasticsearch.tasks.Task;
3236
import org.elasticsearch.threadpool.ThreadPool;
3337
import org.elasticsearch.transport.TransportService;
@@ -75,19 +79,45 @@ protected void masterOperation(
7579
LogsStreamsActivationToggleAction.Request request,
7680
ClusterState state,
7781
ActionListener<AcknowledgedResponse> listener
78-
) throws Exception {
82+
) {
7983
ProjectId projectId = projectResolver.getProjectId();
80-
StreamsMetadata streamsState = state.metadata().getProject(projectId).custom(StreamsMetadata.TYPE, StreamsMetadata.EMPTY);
84+
ProjectMetadata projectMetadata = state.metadata().getProject(projectId);
85+
StreamsMetadata streamsState = projectMetadata.custom(StreamsMetadata.TYPE, StreamsMetadata.EMPTY);
8186
boolean currentlyEnabled = streamsState.isLogsEnabled();
8287
boolean shouldEnable = request.shouldEnable();
83-
if (shouldEnable != currentlyEnabled) {
84-
StreamsMetadataUpdateTask updateTask = new StreamsMetadataUpdateTask(request, listener, projectId, shouldEnable);
85-
String taskName = String.format(Locale.ROOT, "enable-streams-logs-[%s]", shouldEnable ? "enable" : "disable");
86-
taskQueue.submitTask(taskName, updateTask, updateTask.timeout());
87-
} else {
88+
89+
if (shouldEnable == currentlyEnabled) {
8890
logger.debug("Logs streams are already in the requested state: {}", shouldEnable);
8991
listener.onResponse(AcknowledgedResponse.TRUE);
92+
return;
93+
}
94+
95+
if (shouldEnable && logsIndexExists(projectMetadata)) {
96+
listener.onFailure(
97+
new ElasticsearchStatusException(
98+
"Cannot enable logs streams: indices named 'logs' or starting with 'logs.' already exist.",
99+
RestStatus.CONFLICT
100+
)
101+
);
102+
return;
90103
}
104+
105+
StreamsMetadataUpdateTask updateTask = new StreamsMetadataUpdateTask(request, listener, projectId, shouldEnable);
106+
String taskName = String.format(Locale.ROOT, "enable-streams-logs-[%s]", shouldEnable ? "enable" : "disable");
107+
taskQueue.submitTask(taskName, updateTask, updateTask.timeout());
108+
}
109+
110+
private boolean logsIndexExists(ProjectMetadata projectMetadata) {
111+
String logsStreamName = StreamType.LOGS.getStreamName();
112+
String logsStreamPrefix = logsStreamName + ".";
113+
114+
for (String name : projectMetadata.getConcreteAllIndices()) {
115+
if (name.equals(logsStreamName) || name.startsWith(logsStreamPrefix)) {
116+
return true;
117+
}
118+
}
119+
120+
return false;
91121
}
92122

93123
@Override
@@ -111,7 +141,7 @@ static class StreamsMetadataUpdateTask extends AckedClusterStateUpdateTask {
111141
}
112142

113143
@Override
114-
public ClusterState execute(ClusterState currentState) throws Exception {
144+
public ClusterState execute(ClusterState currentState) {
115145
return currentState.copyAndUpdateProject(
116146
projectId,
117147
builder -> builder.putCustom(StreamsMetadata.TYPE, new StreamsMetadata(enabled))

modules/streams/src/yamlRestTest/resources/rest-api-spec/test/streams/logs/10_basic.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
---
2+
teardown:
3+
- do:
4+
streams.logs_disable: { }
5+
16
---
27
"Basic toggle of logs state enable to disable and back":
38
- do:
@@ -24,6 +29,10 @@
2429
streams.status: { }
2530
- is_true: logs.enabled
2631

32+
- do:
33+
streams.logs_disable: { }
34+
- is_true: acknowledged
35+
2736
---
2837
"Check for repeated toggle to same state":
2938
- do:
@@ -41,3 +50,35 @@
4150
- do:
4251
streams.status: { }
4352
- is_true: logs.enabled
53+
54+
- do:
55+
streams.logs_disable: { }
56+
- is_true: acknowledged
57+
58+
---
59+
"Check streams can't be enabled with existing logs indices":
60+
- do:
61+
indices.create:
62+
index: logs
63+
64+
- do:
65+
catch: conflict
66+
streams.logs_enable: { }
67+
- match: { error.reason: "Cannot enable logs streams: indices named 'logs' or starting with 'logs.' already exist." }
68+
69+
- do:
70+
indices.delete:
71+
index: logs
72+
73+
- do:
74+
indices.create:
75+
index: logs.test
76+
77+
- do:
78+
catch: conflict
79+
streams.logs_enable: { }
80+
- match: { error.reason: "Cannot enable logs streams: indices named 'logs' or starting with 'logs.' already exist." }
81+
82+
- do:
83+
indices.delete:
84+
index: logs.test

modules/streams/src/yamlRestTest/resources/rest-api-spec/test/streams/logs/20_substream_restrictions.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
---
2+
teardown:
3+
- do:
4+
streams.logs_disable: { }
5+
16
---
27
"Check User Can't Write To Substream Directly":
38
- do:
@@ -71,6 +76,10 @@
7176
- match: { items.0.index.error.type: "illegal_argument_exception" }
7277
- match: { items.0.index.error.reason: "Pipeline [reroute-to-logs-foo] can't change the target index (from [bad-index] to [logs] child stream [logs.foo]) History: [bad-index]" }
7378

79+
- do:
80+
indices.delete:
81+
index: bad-index
82+
7483
---
7584
"Check Bulk Index With Script Processor To Substream Is Rejected":
7685
- do:
@@ -104,6 +113,10 @@
104113
- match: { items.0.index.error.type: "illegal_argument_exception" }
105114
- match: { items.0.index.error.reason: "Pipeline [script-to-logs-foo] can't change the target index (from [bad-index-script] to [logs] child stream [logs.foo]) History: [bad-index-script]" }
106115

116+
- do:
117+
indices.delete:
118+
index: bad-index-script
119+
107120
---
108121
"Check Delete By Query Directly On Substream After Reroute Succeeds":
109122
- do:
@@ -154,3 +167,7 @@
154167
query:
155168
match_all: {}
156169
- match: { hits.total.value: 0 }
170+
171+
- do:
172+
indices.delete:
173+
index: logs

server/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
exports org.elasticsearch.common.regex;
214214
exports org.elasticsearch.common.scheduler;
215215
exports org.elasticsearch.common.settings;
216+
exports org.elasticsearch.common.streams;
216217
exports org.elasticsearch.common.text;
217218
exports org.elasticsearch.common.time;
218219
exports org.elasticsearch.common.transport;

0 commit comments

Comments
 (0)