Skip to content

[UII] Support searchAfter and PIT (point-in-time) parameters for get agents list API#213486

Merged
jen-huang merged 16 commits intoelastic:mainfrom
jen-huang:feat/agents-pit
Mar 8, 2025
Merged

[UII] Support searchAfter and PIT (point-in-time) parameters for get agents list API#213486
jen-huang merged 16 commits intoelastic:mainfrom
jen-huang:feat/agents-pit

Conversation

@jen-huang
Copy link
Contributor

@jen-huang jen-huang commented Mar 6, 2025

Summary

Resolves #206924.

This PR adds the following query parameters to the agent list API (GET /api/fleet/agents) in order to enable fetching beyond the first 10,000 hits:

    searchAfter?: string;
    openPit?: boolean;
    pitId?: string;
    pitKeepAlive?: string;

The list agent API response can now include the following properties

    // the PIT ID used
    pit?: string;

    // stringified version of the last agent's `sort` field,
    // can be passed as `searchAfter` in the next request
    nextSearchAfter? string;
  • searchAfter can be used with or without a pitId. If using searchAfter, page parameter is not accepted.

  • searchAfter expects a stringified array. (Reviewers: I couldn't get the Kibana request schema to accept a multi-part query param and convert it to an array... I think this would be better, please let me know if you know how to get that to work 🙏)

  • pitKeepAlive duration (i.e. 30s, 1m, etc) must be present when opening a PIT or retrieving results using a PIT ID.

  • These can be used with the existing sortField and sortOrder params. They default to enrolled_at and desc respectively.

Example using only searchAfter:

# Retrieve the first 10k hits
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000'

# Grab the `nextSearchAfter` param from the response
# Pass it to the new request to retrieve the next page of 10k hits
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000&searchAfter=<nextSearchAfter>'

Example using searchAfter with point-in-time parameters:

# Retrieve the first 10k hits and open a PIT
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000&openPit=true&pitKeepAlive=5m'

# Grab the `pit` ID from the response
# Grab the `nextSearchAfter` param from the response
# Pass both to the new request to retrieve the next page of 10k hits
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000&searchAfter=<nextSearchAfter>&pitId=<pit id>&pitKeepAlive=5m'

Testing

I recommend using scripts/create_agents to generate bulk agents and testing the above requests. You can generate new agents between PIT requests to test that using a PIT ID retains the original state. (An API functional test was added for this)

Note: you may need to add &showInactive=true to all requests if your fake agents become inactive.

TBD

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

  • Unit or functional tests were updated or added to match the most common scenarios
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
@jen-huang jen-huang self-assigned this Mar 7, 2025
@jen-huang jen-huang added release_note:enhancement backport:skip This PR does not require backporting Team:Fleet Team label for Observability Data Collection Fleet team labels Mar 7, 2025
@jen-huang jen-huang marked this pull request as ready for review March 7, 2025 00:25
@jen-huang jen-huang requested a review from a team as a code owner March 7, 2025 00:25
@elasticmachine
Copy link
Contributor

Pinging @elastic/fleet (Team:Fleet)

getStatusSummary: schema.boolean({ defaultValue: false }),
sortField: schema.maybe(schema.string()),
sortOrder: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])),
searchAfter: schema.maybe(schema.string()),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

reposting from PR description:

@elastic/fleet I couldn't get the Kibana request schema to accept a multi-part query param and convert it to an array... I think this would be better, please let me know if you know how to get that to work 🙏

changing this to schema.maybe(schema.arrayOf(schema.any())) and passing params like &searchAfter=123&searchAfter=test or even &searchAfter[]=123&searchAfter[]=test didn't work. it only returned error about searchAfter not matching expected schema

Copy link
Member

Choose a reason for hiding this comment

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

it seems when using an array of any it do not parse correctly number or string, (it seems expected as there not really way to get that), so I guess it's okay to use a string here I am wondering if it will make the API easier to use if we add a meta to agent list response something like nextSearchAfter: "[stringified...]" so user will not have to know about getting the last sort field of the agents, WDYT?

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 think this is a good idea, I will take a look

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nchaulet added in 0783feb and updated PR description. it helped writing the API tests a little easier too :)

@jen-huang
Copy link
Contributor Author

/ci test this

…t --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions --include-path /api/security/role --include-path /api/spaces --include-path /api/fleet --include-path /api/dashboards --update'
@nchaulet nchaulet self-requested a review March 7, 2025 13:04
jen-huang and others added 6 commits March 7, 2025 13:12
…t --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions --include-path /api/security/role --include-path /api/spaces --include-path /api/fleet --include-path /api/dashboards --update'
Copy link
Member

@nchaulet nchaulet left a comment

Choose a reason for hiding this comment

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

code LGTM 🚀 should we add some doc for that? having a recipe in the doc on how to query for more than 10k agents could be a good idea

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
fleet 1337 1339 +2
Unknown metric groups

API count

id before after diff
fleet 1465 1467 +2

History

cc @jen-huang

@jen-huang
Copy link
Contributor Author

should we add some doc for that? having a recipe in the doc on how to query for more than 10k agents could be a good idea

I filed elastic/ingest-docs#1726. Thanks for quick re-review!

@jen-huang jen-huang merged commit 3f90203 into elastic:main Mar 8, 2025
9 checks passed
@jen-huang jen-huang deleted the feat/agents-pit branch March 8, 2025 00:01
CAWilson94 pushed a commit to CAWilson94/kibana that referenced this pull request Mar 22, 2025
…t agents list API (elastic#213486)

## Summary

Resolves elastic#206924.

This PR adds the following query parameters to the agent list API (`GET
/api/fleet/agents`) in order to enable fetching beyond the first 10,000
hits:
```
    searchAfter?: string;
    openPit?: boolean;
    pitId?: string;
    pitKeepAlive?: string;
```

The list agent API response can now include the following properties
```
    // the PIT ID used
    pit?: string;

    // stringified version of the last agent's `sort` field,
    // can be passed as `searchAfter` in the next request
    nextSearchAfter? string;
```

* `searchAfter` can be used with or without a `pitId`. If using
`searchAfter`, `page` parameter is not accepted.

* `searchAfter` expects a stringified array. (Reviewers: I couldn't get
the Kibana request schema to accept a multi-part query param and convert
it to an array... I think this would be better, please let me know if
you know how to get that to work 🙏)

* `pitKeepAlive` duration (i.e. `30s`, `1m`, etc) must be present when
opening a PIT or retrieving results using a PIT ID.

* These can be used with the existing `sortField` and `sortOrder`
params. They default to `enrolled_at` and `desc` respectively.

### Example using only `searchAfter`:

```
# Retrieve the first 10k hits
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000'

# Grab the `nextSearchAfter` param from the response
# Pass it to the new request to retrieve the next page of 10k hits
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000&searchAfter=<nextSearchAfter>'
```

### Example using `searchAfter` with point-in-time parameters:
```
# Retrieve the first 10k hits and open a PIT
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000&openPit=true&pitKeepAlive=5m'

# Grab the `pit` ID from the response
# Grab the `nextSearchAfter` param from the response
# Pass both to the new request to retrieve the next page of 10k hits
curl -X GET 'http://<user>:<pass>@<kibana url>/api/fleet/agents?perPage=10000&searchAfter=<nextSearchAfter>&pitId=<pit id>&pitKeepAlive=5m'
```

## Testing
I recommend using `scripts/create_agents` to generate bulk agents and
testing the above requests. You can generate new agents between PIT
requests to test that using a PIT ID retains the original state. (An API
functional test was added for this)

Note: you may need to add `&showInactive=true` to all requests if your
fake agents become inactive.

TBD

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:enhancement Team:Fleet Team label for Observability Data Collection Fleet team v9.1.0

4 participants