Skip to content

🌊 Make client check for hierarchy conflicts before creating streams#208914

Merged
miltonhultgren merged 8 commits intoelastic:mainfrom
miltonhultgren:streams-assert-hierarchy-conflicts
Feb 5, 2025
Merged

🌊 Make client check for hierarchy conflicts before creating streams#208914
miltonhultgren merged 8 commits intoelastic:mainfrom
miltonhultgren:streams-assert-hierarchy-conflicts

Conversation

@miltonhultgren
Copy link
Contributor

@miltonhultgren miltonhultgren commented Jan 30, 2025

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.

@miltonhultgren miltonhultgren requested review from a team as code owners January 30, 2025 11:31
@miltonhultgren miltonhultgren added release_note:skip Skip the PR/issue when compiling release notes backport:prev-minor Feature:Streams This is the label for the Streams Project labels Jan 30, 2025
private async assertNoHierarchicalConflicts(definitionName: string) {
const streamNames = [...getAncestors(definitionName), definitionName];
const hasConflict = await Promise.all(
streamNames.map((streamName) => this.isStreamNameTaken(streamName))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +369 to +377
if (!isDefinitionNotFoundError(error)) {
throw error;
}
}

try {
await this.dependencies.scopedClusterClient.asCurrentUser.indices.get({
index: streamName,
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

@tonyghiani tonyghiani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 👌

Copy link
Contributor

@tonyghiani tonyghiani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 👌

Copy link
Contributor

@tonyghiani tonyghiani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the changes 👌

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above

@elasticmachine
Copy link
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Jest Tests #15 / Configure renders correctly

Metrics [docs]

✅ unchanged

History

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@miltonhultgren miltonhultgren merged commit 3c4694e into elastic:main Feb 5, 2025
1 check passed
@kibanamachine
Copy link
Contributor

Starting backport for target branches: 9.0

https://github.com/elastic/kibana/actions/runs/13159058514

@kibanamachine
Copy link
Contributor

💔 All backports failed

Status Branch Result
9.0 Backport failed because of merge conflicts

You might need to backport the following PRs to 9.0:
- [Streams 🌊] Introduce GroupStreams (#208126)

Manual backport

To create the backport manually run:

node scripts/backport --pr 208914

Questions ?

Please refer to the Backport tool documentation

@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.16, 8.17, 8.18, 8.x

https://github.com/elastic/kibana/actions/runs/13176143714

@kibanamachine
Copy link
Contributor

💔 All backports failed

Status Branch Result
8.16 Backport failed because of merge conflicts

You might need to backport the following PRs to 8.16:
- [OBX-UX-MGMT][BUG] Fix chart in Custom Threshold rule when the field name has slashes (#209263)
8.17 Backport failed because of merge conflicts

You might need to backport the following PRs to 8.17:
- [Detection Engine][Docs] Updating examples to meet old ascii docs (#207558)
- [OBX-UX-MGMT][BUG] Fix chart in Custom Threshold rule when the field name has slashes (#209263)
8.18 Backport failed because of merge conflicts
8.x Backport failed because of merge conflicts

You might need to backport the following PRs to 8.x:
- [Streams 🌊] Introduce GroupStreams (#208126)

Manual backport

To create the backport manually run:

node scripts/backport --pr 208914

Questions ?

Please refer to the Backport tool documentation

@miltonhultgren miltonhultgren added backport:version Backport to applied version labels v8.19.0 and removed backport:prev-major labels Feb 6, 2025
@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.x

https://github.com/elastic/kibana/actions/runs/13176673344

@kibanamachine
Copy link
Contributor

💔 All backports failed

Status Branch Result
8.x Backport failed because of merge conflicts

You might need to backport the following PRs to 8.x:
- [Streams 🌊] Introduce GroupStreams (#208126)

Manual backport

To create the backport manually run:

node scripts/backport --pr 208914

Questions ?

Please refer to the Backport tool documentation

@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.x

https://github.com/elastic/kibana/actions/runs/13176673344

kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Feb 6, 2025
…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)
@kibanamachine
Copy link
Contributor

💚 All backports created successfully

Status Branch Result
8.x

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

kibanamachine added a commit that referenced this pull request Feb 6, 2025
…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>
drewdaemon pushed a commit to drewdaemon/kibana that referenced this pull request Feb 6, 2025
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:version Backport to applied version labels Feature:Streams This is the label for the Streams Project release_note:skip Skip the PR/issue when compiling release notes v8.19.0 v9.1.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants