mirror of
https://github.com/rancher/steve.git
synced 2025-09-23 12:29:09 +00:00
Further fixes to the projectsornamespaces param, with new tests. (#772)
* Further fixes to the projectsornamespaces param, with new tests. * Simplify projectsornamespaces on namespace kind Move the processing of this special case from the SQL code generator to the parser, and map it to simple `metadata.name=` and `metadata.labels[...]` tests. * Fix `projectsornamespace!=` code gen. These should generate (f.namespace != X AND (negative label test). The code was generating an `OR` giving too many false positives. * Fix the projORns not error in the SQL
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/rancher/steve/pkg/stores/queryhelper"
|
||||
"github.com/rancher/steve/pkg/stores/sqlpartition/queryparser"
|
||||
"github.com/rancher/steve/pkg/stores/sqlpartition/selection"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
@@ -77,7 +78,7 @@ func k8sRequirementToOrFilter(requirement queryparser.Requirement) (sqltypes.Fil
|
||||
}
|
||||
|
||||
// ParseQuery parses the query params of a request and returns a ListOptions.
|
||||
func ParseQuery(apiOp *types.APIRequest) (sqltypes.ListOptions, error) {
|
||||
func ParseQuery(apiOp *types.APIRequest, gvKind string) (sqltypes.ListOptions, error) {
|
||||
opts := sqltypes.ListOptions{}
|
||||
|
||||
q := apiOp.Request.URL.Query()
|
||||
@@ -146,7 +147,23 @@ func ParseQuery(apiOp *types.APIRequest) (sqltypes.ListOptions, error) {
|
||||
}
|
||||
}
|
||||
if projectsOrNamespaces != "" {
|
||||
opts.ProjectsOrNamespaces = parseNamespaceOrProjectFilters(projectsOrNamespaces, op)
|
||||
if gvKind == "Namespace" {
|
||||
projNSFilter := parseNamespaceOrProjectFilters(projectsOrNamespaces, op)
|
||||
if len(projNSFilter.Filters) == 2 {
|
||||
if op == sqltypes.In {
|
||||
opts.Filters = append(opts.Filters, projNSFilter)
|
||||
} else {
|
||||
opts.Filters = append(opts.Filters, sqltypes.OrFilter{Filters: []sqltypes.Filter{projNSFilter.Filters[0]}})
|
||||
opts.Filters = append(opts.Filters, sqltypes.OrFilter{Filters: []sqltypes.Filter{projNSFilter.Filters[1]}})
|
||||
}
|
||||
} else if len(projNSFilter.Filters) == 0 {
|
||||
// do nothing
|
||||
} else {
|
||||
logrus.Infof("Ignoring unexpected filter for query %q: parseNamespaceOrProjectFilters returned %d filters, expecting 2", q, len(projNSFilter.Filters))
|
||||
}
|
||||
} else {
|
||||
opts.ProjectsOrNamespaces = parseNamespaceOrProjectFilters(projectsOrNamespaces, op)
|
||||
}
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
|
@@ -16,6 +16,7 @@ func TestParseQuery(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
req *types.APIRequest
|
||||
gvKind string // This is to distinguish Namespace projectornamespaces from others
|
||||
expectedLO sqltypes.ListOptions
|
||||
errExpected bool
|
||||
errorText string
|
||||
@@ -63,6 +64,118 @@ func TestParseQuery(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
description: "ParseQuery() with only projectsornamespaces on a namespace GVK should return a standard filter.",
|
||||
req: &types.APIRequest{
|
||||
Request: &http.Request{
|
||||
URL: &url.URL{RawQuery: "projectsornamespaces=elm&filter=metadata.name~beech"},
|
||||
},
|
||||
},
|
||||
gvKind: "Namespace",
|
||||
expectedLO: sqltypes.ListOptions{
|
||||
Filters: []sqltypes.OrFilter{
|
||||
{
|
||||
Filters: []sqltypes.Filter{
|
||||
{
|
||||
Field: []string{"metadata", "name"},
|
||||
Matches: []string{"beech"},
|
||||
Op: sqltypes.Eq,
|
||||
Partial: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filters: []sqltypes.Filter{
|
||||
{
|
||||
Field: []string{"metadata", "name"},
|
||||
Matches: []string{"elm"},
|
||||
Op: sqltypes.In,
|
||||
},
|
||||
{
|
||||
Field: []string{"metadata", "labels", "field.cattle.io/projectId"},
|
||||
Matches: []string{"elm"},
|
||||
Op: sqltypes.In,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Pagination: sqltypes.Pagination{
|
||||
Page: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
description: "ParseQuery() with only a negative projectsornamespaces should return a project/ns filter.",
|
||||
req: &types.APIRequest{
|
||||
Request: &http.Request{
|
||||
URL: &url.URL{RawQuery: "projectsornamespaces!=somethin"},
|
||||
},
|
||||
},
|
||||
expectedLO: sqltypes.ListOptions{
|
||||
Filters: []sqltypes.OrFilter{},
|
||||
ProjectsOrNamespaces: sqltypes.OrFilter{
|
||||
Filters: []sqltypes.Filter{
|
||||
{
|
||||
Field: []string{"metadata", "name"},
|
||||
Matches: []string{"somethin"},
|
||||
Op: sqltypes.NotIn,
|
||||
},
|
||||
{
|
||||
Field: []string{"metadata", "labels", "field.cattle.io/projectId"},
|
||||
Matches: []string{"somethin"},
|
||||
Op: sqltypes.NotIn,
|
||||
},
|
||||
},
|
||||
},
|
||||
Pagination: sqltypes.Pagination{
|
||||
Page: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
description: "ParseQuery() with only negative projectsornamespaces on a namespace GVK should return a standard filter.",
|
||||
req: &types.APIRequest{
|
||||
Request: &http.Request{
|
||||
URL: &url.URL{RawQuery: "projectsornamespaces!=elm&filter=metadata.name~beech"},
|
||||
},
|
||||
},
|
||||
gvKind: "Namespace",
|
||||
expectedLO: sqltypes.ListOptions{
|
||||
Filters: []sqltypes.OrFilter{
|
||||
{
|
||||
Filters: []sqltypes.Filter{
|
||||
{
|
||||
Field: []string{"metadata", "name"},
|
||||
Matches: []string{"beech"},
|
||||
Op: sqltypes.Eq,
|
||||
Partial: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filters: []sqltypes.Filter{
|
||||
{
|
||||
Field: []string{"metadata", "name"},
|
||||
Matches: []string{"elm"},
|
||||
Op: sqltypes.NotIn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filters: []sqltypes.Filter{
|
||||
{
|
||||
Field: []string{"metadata", "labels", "field.cattle.io/projectId"},
|
||||
Matches: []string{"elm"},
|
||||
Op: sqltypes.NotIn,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Pagination: sqltypes.Pagination{
|
||||
Page: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
description: "ParseQuery() with filter param set should include filter with partial set to true in list options.",
|
||||
req: &types.APIRequest{
|
||||
@@ -758,7 +871,7 @@ func TestParseQuery(t *testing.T) {
|
||||
//if test.description == "ParseQuery() with no errors: if projectsornamespaces is not empty, it should return an empty filter array" {
|
||||
// fmt.Println("stop here")
|
||||
//}
|
||||
lo, err := ParseQuery(test.req)
|
||||
lo, err := ParseQuery(test.req, test.gvKind)
|
||||
if test.errExpected {
|
||||
assert.NotNil(t, err)
|
||||
if test.errorText != "" {
|
||||
|
Reference in New Issue
Block a user