Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pagination fixes #127

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Pagination fixes #127

wants to merge 3 commits into from

Conversation

cmurphy
Copy link
Contributor

@cmurphy cmurphy commented Sep 18, 2023

Allow for filtering/sorting by reserved fields

Certain fields like "type" in an object are reserved by
rancher/apiserver and so are transmuted to an underscore-prefixed
version of the field name, e.g. "_type", which is what appears in the
HTTP response output. Objects like Secrets, which have a built-in Type
field, are subject to this.

Without this patch, filtering and sorting are done on the object prior
to the field renaming, so filtering by "_type" would result in no
filtering happening even though the output returned to the user does
contain "_type". This change ensures that the field name changes happen
before filtering and sorting is started.

Add support for filtering/sorting by array index

For an object like

"status": {
    "podIPs": [
        "10.0.0.1",
        "10.0.0.2",
        "10.0.0.3",
    ]
}

add the ability to filter or sort by a single element in the array list:

GET /pods?filter=status.podIPs.2=10.0.0.2
GET /pods?sort=status.podIPs.2

rancher/rancher#42767
Depends on rancher/wrangler#321

go.mod Outdated
@@ -6,6 +6,7 @@ replace (
github.com/crewjam/saml => github.com/rancher/saml v0.2.0
github.com/knative/pkg => github.com/rancher/pkg v0.0.0-20181214184433-b04c0947ad2f
github.com/matryer/moq => github.com/rancher/moq v0.0.0-20190404221404-ee5226d43009
github.com/rancher/wrangler => github.com/cmurphy/wrangler v0.8.1-0.20230918211505-408ec3feeca5
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix this before merging

@@ -260,17 +260,15 @@ func getLimit(apiOp *types.APIRequest) int {

// FilterList accepts a channel of unstructured objects and a slice of filters and returns the filtered list.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is no longer a channel

Suggested change
// FilterList accepts a channel of unstructured objects and a slice of filters and returns the filtered list.
// FilterList accepts a slice of unstructured objects and a slice of filters and returns the filtered list.

result = append(result, item)
}
for _, item := range list {
if len(filters) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since filters never changes in size, this could be moved out of the for loop

if len(filters) == 0 {
  return list
}

@@ -124,7 +124,7 @@ func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string
if err != nil {
return types.APIObject{}, err
}
return toAPI(schema, obj, warnings), nil
return toAPI(schema, moveToUnderscore(obj), warnings), nil
Copy link
Contributor

Choose a reason for hiding this comment

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

If this looks up a single object, do we need to do moveToUnderscore? I noticed we don't for List and Watch

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 single object could contain a reserved key, so it needs to be moved. For List, moveToUnderscore was moved out of toAPI and into preprocessList. for Watch, it's under toAPIEvent.

@samjustus samjustus requested review from rmweir and removed request for KevinJoiner September 29, 2023 14:11
@cmurphy cmurphy requested a review from a team as a code owner April 9, 2024 21:29
For an object like

```
"status": {
    "podIPs": [
        "10.0.0.1",
        "10.0.0.2",
        "10.0.0.3",
    ]
}
```

add the ability to filter or sort by a single element in the array list:

```
GET /pods?filter=status.podIPs.2=10.0.0.2
GET /pods?sort=status.podIPs.2
```
Certain fields like "type" in an object are reserved by
rancher/apiserver and so are transmuted to an underscore-prefixed
version of the field name, e.g. "_type", which is what appears in the
HTTP response output. Objects like Secrets, which have a built-in Type
field, are subject to this.

Without this patch, filtering and sorting are done on the object prior
to the field renaming, so filtering by "_type" would result in no
filtering happening even though the output returned to the user does
contain "_type". This change ensures that the field name changes happen
before filtering and sorting is started.
Copy link
Contributor

@tomleb tomleb left a comment

Choose a reason for hiding this comment

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

LGTM

go.mod Outdated Show resolved Hide resolved
Comment on lines +264 to +266
if len(filters) == 0 {
return list
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Observation: The behavior is slightly different than before because here we're returning the same list (with the same storage behind) whereas before we were returning a new list (different storage).

This doesn't seem to be an issue in this case, and we're doing the same in other places (eg: FilterByProjectsAndNamespaces)

Copy link
Contributor

Choose a reason for hiding this comment

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

Before I think we had a difference in return vs input type, so that wasn't really possible there. Ordinarily I would fix a small inconsistency like this to avoid difficult-to-locate bugs (like someone changing the original list in a go-routine and not realizing that it affected other values down-the-line), but I think there's a performance impact here to consider - copying the items to another list would have a non-zero performance impact. I would also expect the "no filters" case to be the default for the time being, so I'd like to keep this as-is and avoid a costly copy operation.

WDYT?

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 okay as is. I think consistency would be better from my POV. The costly copy was already there, so adding it back wouldn't make rancher perform worse than it already is. We could benchmark it and see how much optimizing this improves the performance in the grand scheme of things but I'd rather do that as a separate issue and as a need basis.

Copy link
Contributor

Choose a reason for hiding this comment

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

Without benchmark, it's usually difficult to know if an optimization improves or not. For example, the compiler could already be optimizing this part of the code. It's hard to tell without benchmarks.

Also adds a new test for a nested array/map filter.
@MbolotSuse MbolotSuse requested a review from tomleb April 10, 2024 18:12
Copy link
Contributor

@JonCrowther JonCrowther left a comment

Choose a reason for hiding this comment

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

Refreshing my approval. Needs a rebase but otherwise LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants