🌊 Make client check for hierarchy conflicts before creating streams#208914
Conversation
| private async assertNoHierarchicalConflicts(definitionName: string) { | ||
| const streamNames = [...getAncestors(definitionName), definitionName]; | ||
| const hasConflict = await Promise.all( | ||
| streamNames.map((streamName) => this.isStreamNameTaken(streamName)) |
There was a problem hiding this comment.
Small note: If we used arrow functions to define our methods we could write this simply as streamNames.map(this.isStreamNameTaken) since the context would already be bound.
There was a problem hiding this comment.
I'm always in favour of referencing functions vs inline callbacks, I wouldn't mind if you change the method declaration to an arrow function.
| if (!isDefinitionNotFoundError(error)) { | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| await this.dependencies.scopedClusterClient.asCurrentUser.indices.get({ | ||
| index: streamName, | ||
| }); |
There was a problem hiding this comment.
I'm not super happy with the side effect driven flow here but flipping it just feels so verbose.
| return this.dependencies.scopedClusterClient.asCurrentUser.indices | ||
| .getDataStream({ name }) | ||
| .then((response) => { | ||
| if (response.data_streams.length === 0) { |
There was a problem hiding this comment.
This is where the original error came from, if there is no data stream this API does not throw any error, it simply returns an empty list.
Which caused the flow to continue to try to translate this undefined object into a Classic stream definition hence causing the undefined.name error.
| const { streamsClient } = await getScopedClients({ request }); | ||
|
|
||
| if (!(await streamsClient.isStreamsEnabled())) { | ||
| throw badData('Streams are not enabled'); |
There was a problem hiding this comment.
badData results in a HTTP 422, since the request is syntactically correct and would pass our validation but there is a semantic error of streams not being enabled yet.
x-pack/solutions/observability/plugins/streams/server/routes/streams/enablement/route.ts
Outdated
Show resolved
Hide resolved
x-pack/solutions/observability/plugins/streams/server/routes/streams/crud/route.ts
Outdated
Show resolved
Hide resolved
tonyghiani
left a comment
There was a problem hiding this comment.
Overall looks good, you got some test failures, I'll give another quick review once it's solved but it should be good to go 👌
tonyghiani
left a comment
There was a problem hiding this comment.
Overall looks good, you got some test failures, I'll give another quick review once it's solved but it should be good to go 👌
tonyghiani
left a comment
There was a problem hiding this comment.
LGTM, thanks for the changes 👌
x-pack/solutions/observability/plugins/streams/server/lib/streams/root_stream_definition.ts
Outdated
Show resolved
Hide resolved
x-pack/solutions/observability/plugins/streams/server/lib/streams/client.ts
Outdated
Show resolved
Hide resolved
💛 Build succeeded, but was flaky
Failed CI StepsTest FailuresMetrics [docs]
History
|
|
Starting backport for target branches: 9.0 https://github.com/elastic/kibana/actions/runs/13159058514 |
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
|
Starting backport for target branches: 8.16, 8.17, 8.18, 8.x https://github.com/elastic/kibana/actions/runs/13176143714 |
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
|
Starting backport for target branches: 8.x https://github.com/elastic/kibana/actions/runs/13176673344 |
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
|
Starting backport for target branches: 8.x https://github.com/elastic/kibana/actions/runs/13176673344 |
…lastic#208914) ## Summary If you enable streams (which creates `logs`) and then try to create `logs.child.grandchild` but `logs.child` already exists as either an index or an unwired (Classic) stream, then we end up in a weird state where `logs.child.grandchild` gets created as a wired child but then the request fails as it tries to turn the unwired stream into a wired stream. This PR adds a step that asserts that there are no such conflicts in the hierarchy before proceeding. It also adds a check to ensure Streams are enabled before allowing the creation of any streams, as well as blocking the creation of a root stream that isn't `logs`. Finally, there is some minor improvements to error handling for when a data stream isn't found and error messages. (cherry picked from commit 3c4694e)
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
…eams (#208914) (#210003) # Backport This will backport the following commits from `main` to `8.x`: - [🌊 Make client check for hierarchy conflicts before creating streams (#208914)](#208914) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Milton Hultgren","email":"milton.hultgren@elastic.co"},"sourceCommit":{"committedDate":"2025-02-05T14:01:47Z","message":"🌊 Make client check for hierarchy conflicts before creating streams (#208914)\n\n## Summary\r\n\r\nIf you enable streams (which creates `logs`) and then try to create\r\n`logs.child.grandchild` but `logs.child` already exists as either an\r\nindex or an unwired (Classic) stream, then we end up in a weird state\r\nwhere `logs.child.grandchild` gets created as a wired child but then the\r\nrequest fails as it tries to turn the unwired stream into a wired\r\nstream.\r\n\r\nThis PR adds a step that asserts that there are no such conflicts in the\r\nhierarchy before proceeding.\r\nIt also adds a check to ensure Streams are enabled before allowing the\r\ncreation of any streams, as well as blocking the creation of a root\r\nstream that isn't `logs`.\r\nFinally, there is some minor improvements to error handling for when a\r\ndata stream isn't found and error messages.","sha":"3c4694e1ddee4cd956c4b70d7f5c0f521f504212","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport:version","Feature:Streams","v9.1.0","v8.19.0"],"title":"🌊 Make client check for hierarchy conflicts before creating streams","number":208914,"url":"https://github.com/elastic/kibana/pull/208914","mergeCommit":{"message":"🌊 Make client check for hierarchy conflicts before creating streams (#208914)\n\n## Summary\r\n\r\nIf you enable streams (which creates `logs`) and then try to create\r\n`logs.child.grandchild` but `logs.child` already exists as either an\r\nindex or an unwired (Classic) stream, then we end up in a weird state\r\nwhere `logs.child.grandchild` gets created as a wired child but then the\r\nrequest fails as it tries to turn the unwired stream into a wired\r\nstream.\r\n\r\nThis PR adds a step that asserts that there are no such conflicts in the\r\nhierarchy before proceeding.\r\nIt also adds a check to ensure Streams are enabled before allowing the\r\ncreation of any streams, as well as blocking the creation of a root\r\nstream that isn't `logs`.\r\nFinally, there is some minor improvements to error handling for when a\r\ndata stream isn't found and error messages.","sha":"3c4694e1ddee4cd956c4b70d7f5c0f521f504212"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/208914","number":208914,"mergeCommit":{"message":"🌊 Make client check for hierarchy conflicts before creating streams (#208914)\n\n## Summary\r\n\r\nIf you enable streams (which creates `logs`) and then try to create\r\n`logs.child.grandchild` but `logs.child` already exists as either an\r\nindex or an unwired (Classic) stream, then we end up in a weird state\r\nwhere `logs.child.grandchild` gets created as a wired child but then the\r\nrequest fails as it tries to turn the unwired stream into a wired\r\nstream.\r\n\r\nThis PR adds a step that asserts that there are no such conflicts in the\r\nhierarchy before proceeding.\r\nIt also adds a check to ensure Streams are enabled before allowing the\r\ncreation of any streams, as well as blocking the creation of a root\r\nstream that isn't `logs`.\r\nFinally, there is some minor improvements to error handling for when a\r\ndata stream isn't found and error messages.","sha":"3c4694e1ddee4cd956c4b70d7f5c0f521f504212"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Milton Hultgren <milton.hultgren@elastic.co>
…lastic#208914) ## Summary If you enable streams (which creates `logs`) and then try to create `logs.child.grandchild` but `logs.child` already exists as either an index or an unwired (Classic) stream, then we end up in a weird state where `logs.child.grandchild` gets created as a wired child but then the request fails as it tries to turn the unwired stream into a wired stream. This PR adds a step that asserts that there are no such conflicts in the hierarchy before proceeding. It also adds a check to ensure Streams are enabled before allowing the creation of any streams, as well as blocking the creation of a root stream that isn't `logs`. Finally, there is some minor improvements to error handling for when a data stream isn't found and error messages.
Summary
If you enable streams (which creates
logs) and then try to createlogs.child.grandchildbutlogs.childalready exists as either an index or an unwired (Classic) stream, then we end up in a weird state wherelogs.child.grandchildgets created as a wired child but then the request fails as it tries to turn the unwired stream into a wired stream.This PR adds a step that asserts that there are no such conflicts in the hierarchy before proceeding.
It also adds a check to ensure Streams are enabled before allowing the creation of any streams, as well as blocking the creation of a root stream that isn't
logs.Finally, there is some minor improvements to error handling for when a data stream isn't found and error messages.