Skip to content
This repository has been archived by the owner on Sep 21, 2023. It is now read-only.

Elasticsearch output #137

Merged
merged 35 commits into from
Oct 27, 2022
Merged

Elasticsearch output #137

merged 35 commits into from
Oct 27, 2022

Conversation

faec
Copy link
Contributor

@faec faec commented Oct 13, 2022

Port of the Elasticsearch output from Beats to the shipper.

Currently it accepts a Beats-style configuration tree, creates an ES client, reads batches from the queue, and sends them to the fixed elastic-agent-shipper index in the target cluster.

This pass does not include:

  • Support for workers / load balancing
  • Detailed batching / timeout / error recovery parameters
  • Most other configuration options that are tied to the internals of the Beats pipeline
  • Beats tests that depend on unimplemented features

Because this code has been uprooted from a completely different setting, much of it is nonfunctional. However, the intent is eventually to fully support the same configurations as the original, so rather than delete all these fields and functions I have left most of them either commented out or idle, so that (vast and trunkless) they can remind us of the work that is still ahead and where it needs to go.

@faec faec self-assigned this Oct 13, 2022
@mergify
Copy link
Contributor

mergify bot commented Oct 13, 2022

This pull request does not have a backport label.
If this is a bug or security fix, could you label this PR @faec? 🙏.
For such, you'll need to label your PR with:

  • The upcoming major version of the Elastic Stack
  • The upcoming minor version of the Elastic Stack (if you're not pushing a breaking change)

To fixup this pull request, you need to add the backport labels for the needed
branches, such as:

  • backport-v8./d.0 is the label to automatically backport to the 8./d branch. /d is the digit

@elasticmachine
Copy link
Collaborator

elasticmachine commented Oct 13, 2022

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2022-10-27T17:39:19.309+0000

  • Duration: 12 min 9 sec

❕ Flaky test report

No test was executed to be analysed.

🤖 GitHub comments

Expand to view the GitHub comments

To re-run your PR in the CI, just comment with:

  • /test : Re-trigger the build.

@jlind23 jlind23 linked an issue Oct 17, 2022 that may be closed by this pull request
@faec faec marked this pull request as ready for review October 24, 2022 20:54
@faec faec requested a review from a team as a code owner October 24, 2022 20:54
@faec faec requested review from belimawr and leehinman and removed request for a team October 24, 2022 20:54
if config.Console != nil && config.Console.Enabled {
return output.NewConsole(queue)
}
if config.Elasticsearch != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason we're just checking for != nil ? I'm imagining a scenario where someone sets output.elasticsearch.enabled: false and it still starts up or something.

Copy link
Contributor Author

@faec faec Oct 25, 2022

Choose a reason for hiding this comment

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

The reason was that the Beats config structures didn't have an Enabled, and if we add one the shipper doesn't have a way to default its value to true the way Beats does. But new outputs will be coming soon so I guess we need to handle this anyway -- I added an enabled flag (which must now be explicitly specified in the config), and revised this check.

@faec faec changed the title Elasticsearch output draft Elasticsearch output Oct 25, 2022
Copy link
Contributor

@leehinman leehinman left a comment

Choose a reason for hiding this comment

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

Probably not for this PR, but it would be nice to get ES started from Docker and add to the integration test.

output/elasticsearch/client.go Outdated Show resolved Hide resolved
}

count := len(data)
failed := data[:0]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
failed := data[:0]
failed := make([]*messages.Event, count)

nit

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 added the other one but I think this one makes sense as-is, there's no need to preallocate anything especially a full-length buffer since this array will usually (knock on wood 😜) be empty

Copy link
Contributor

Choose a reason for hiding this comment

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

I added the other one but I think this one makes sense as-is, there's no need to preallocate anything especially a full-length buffer since this array will usually (knock on wood 😜) be empty

The slice is pre-allocating, that was part of why I proposed the change, the make is a little more declarative.

See https://go.dev/play/p/JXwF_bFUYgE

And of course I screwed up in the suggestion, it should be make([]*messages.Event, 0, len(data)) I forgot the 0 for the length. If we really expect failed to be empty we could do a make with len & cap set to 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.

Sorry, could you elaborate on how an allocation is happening? As I understand it, failed := data[:0] creates a slice but doesn't allocate anything new, it just references the existing array data -- it should cause no heap allocations unless append is called, which creates a new underlying array if needed. I've seen this pattern used as a short way to create an auxiliary list that will often be empty, specifically because it avoids the allocation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, could you elaborate on how an allocation is happening?

🤦 your right, nevermind.

//
// Due to parser simply stepping through the input buffer, almost no additional
// allocations are required.
type jsonReader struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

do we have any unit tests for jsonReader?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we do not :-/

// Config specifies all configurable parameters for the Elasticsearch output.
// Currently these are identical to the parameters in the Beats Elasticsearch
// output, however this is subject to change as we approach official release.
type Config struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

probably want some unit tests for the config validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The config validation is sparse and like in Beats we have no reliable way to evaluate whether a config is valid. For example, other than the baseline validation inherited from the network config, the the ES output validation only checks that at most one of (apikey) and (username+password) are specified. There are many other ways to produce invalid configurations, but we only check them implicitly when the fields are used by the ES client.

All that said, I can still add a test that at least invokes what we have.

Copy link
Member

@cmacknz cmacknz Oct 27, 2022

Choose a reason for hiding this comment

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

One thing we could look at to get an idea of what the "core" Elasticsearch client settings under agent are is the Endpoint security ES client. It is written to support only the configuration that can be provided from an agent policy's output settings. It can be found here (private repository). It doesn't have any of the historical configuration that standalone Beats have accumulated.

This will mostly be the minimum set of parameters specified in the Fleet documentation https://www.elastic.co/guide/en/fleet/current/fleet-settings.html#output-settings. Note that users can put whatever they want in the "Advanced YAML configuration" block, but the UI doesn't validate anything and there is no guarantee that every process running under agent supports them. We likely need to clarify the backwards compatibility guarantees for Advanced YAML configuration, but I am reasonably confident that it is mostly used to specify workers and bulk_max_size for Beats.

Copy link
Member

@cmacknz cmacknz left a comment

Choose a reason for hiding this comment

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

Still going through this, but I found at least two features I think we can drop.

+1 to Lee's suggestion to get an integration test using Docker up, but we can do that as a follow up task.

Since automated tests will come later, what are the steps to test this manually? Are there example Beat+Shipper configs you can share?

output/elasticsearch/dead_letter_selector.go Outdated Show resolved Hide resolved
output/elasticsearch/elasticsearch.go Outdated Show resolved Hide resolved
@faec
Copy link
Contributor Author

faec commented Oct 26, 2022

Since automated tests will come later, what are the steps to test this manually? Are there example Beat+Shipper configs you can share?

The config I've been testing with is:

# filebeat.yml
...
output.shipper:
  server: "localhost:50052"
# elastic-agent-shipper.yml
...
output:
  elasticsearch:
    enabled: true
    hosts: ["https://localhost:9200"]
    username: "elastic"
    password: "[password]"
    allow_older_versions: true
    ssl.verification_mode: none

faec and others added 3 commits October 26, 2022 14:17
Co-authored-by: Lee E Hinman <57081003+leehinman@users.noreply.github.com>
@mergify
Copy link
Contributor

mergify bot commented Oct 27, 2022

This pull request is now in conflicts. Could you fix it? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

git fetch upstream
git checkout -b es-output-staging upstream/es-output-staging
git merge upstream/main
git push upstream es-output-staging

Copy link
Member

@cmacknz cmacknz left a comment

Choose a reason for hiding this comment

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

We'll need to get issues created for all the follow work we need to do, but this is good as a starting point. Thanks!

@faec faec merged commit 0f4c555 into elastic:main Oct 27, 2022
@faec faec deleted the es-output-staging branch October 27, 2022 17:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement an MVP of the Elasticsearch output
5 participants