Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions query/models.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package query

import (
"errors"
"fmt"
"slices"
"strconv"
Expand All @@ -9,7 +10,7 @@ import (

"github.com/flanksource/commons/collections"
"github.com/google/uuid"
"github.com/pkg/errors"
pkgerrors "github.com/pkg/errors"
"github.com/samber/lo"
"github.com/timberio/go-datemath"
"gorm.io/gorm"
Expand All @@ -20,6 +21,10 @@ import (
"github.com/flanksource/duty/query/grammar"
)

// ErrColumnNotSupported is returned when a query references a column that does not exist on the target table.
// Callers can detect this sentinel and skip the resource type rather than propagating the error.
var ErrColumnNotSupported = errors.New("column not supported")

// Maintained by a job
var allTypesCache atomic.Value

Expand Down Expand Up @@ -469,14 +474,14 @@ func (qm QueryModel) Apply(ctx context.Context, q grammar.QueryField, tx *gorm.D
if mapper, ok := CommonFields[q.Field]; ok {
tx, err = mapper(ctx, tx, val)
if err != nil {
return nil, nil, errors.Wrapf(err, "Invalid value for %s", q.Field)
return nil, nil, pkgerrors.Wrapf(err, "Invalid value for %s", q.Field)
}
}

if mapper, ok := qm.Custom[q.Field]; ok {
tx, err = mapper(ctx, tx, val)
if err != nil {
return nil, nil, errors.Wrapf(err, "Invalid value for %s", q.Field)
return nil, nil, pkgerrors.Wrapf(err, "Invalid value for %s", q.Field)
}
}

Expand Down Expand Up @@ -512,7 +517,7 @@ func (qm QueryModel) Apply(ctx context.Context, q grammar.QueryField, tx *gorm.D

if !slices.Contains(ignoreFieldsForClauses, q.Field) {
if !slices.Contains(qm.Columns, q.Field) {
return nil, nil, fmt.Errorf("query for column:%s in table:%s not supported", q.Field, qm.Table)
return nil, nil, fmt.Errorf("query for column:%s in table:%s not supported: %w", q.Field, qm.Table, ErrColumnNotSupported)
}

if q.Field == "type" {
Expand Down
7 changes: 7 additions & 0 deletions query/resource_selector.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package query

import (
"errors"
"fmt"
"slices"
"sort"
Expand Down Expand Up @@ -680,6 +681,9 @@ func queryTableWithResourceSelectors(
for _, resourceSelector := range resourceSelectors {
items, err := queryResourceSelector[uuid.UUID](ctx, limit, []string{"id"}, resourceSelector, table)
if err != nil {
if errors.Is(err, ErrColumnNotSupported) {
continue
}
return nil, err
}

Expand All @@ -705,6 +709,9 @@ func QueryTableColumnsWithResourceSelectors[T any](
for _, resourceSelector := range resourceSelectors {
items, err := queryResourceSelector[T](ctx, limit, selectColumns, resourceSelector, table, clauses...)
if err != nil {
if errors.Is(err, ErrColumnNotSupported) {
continue
}
return nil, err
}

Expand Down
10 changes: 10 additions & 0 deletions tests/query_resource_selector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,16 @@ var _ = ginkgo.Describe("SearchResourceSelectors", func() {
Checks: []models.Check{dummy.LogisticsAPIHealthHTTPCheck},
Configs: []models.ConfigItem{dummy.EKSCluster},
},
{
// #canary #config type=pod — canaries don't have a "type" column so the canary query
// should be silently skipped (no results, no error) while configs still return results.
description: "ignore unsupported type filter for canaries when configs support it",
query: query.SearchResourcesRequest{
Canaries: []types.ResourceSelector{{Search: "type=Kubernetes::Node"}},
Configs: []types.ResourceSelector{{Search: "type=Kubernetes::Node"}},
},
Configs: []models.ConfigItem{dummy.KubernetesNodeA, dummy.KubernetesNodeB, dummy.KubernetesNodeAKSPool1},
},
{
description: "case insensitive | config by id",
query: query.SearchResourcesRequest{
Expand Down
Loading