mirror of
https://github.com/rancher/steve.git
synced 2025-09-12 13:31:57 +00:00
[v2.9] Virtual Resource filters (#288)
Adds logic which adds virtual fields resources. This allows these fields to be sorted/filtered on when the SQL cache is enabled. Id and metadata.state.name were added as the first two fields. Co-authored-by: Michael Bolot <michael.bolot@suse.com>
This commit is contained in:
116
pkg/resources/virtual/common/common.go
Normal file
116
pkg/resources/virtual/common/common.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Package common provides cache.TransformFunc's which are common to all types
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/steve/pkg/summarycache"
|
||||
"github.com/rancher/wrangler/v3/pkg/data"
|
||||
wranglerSummary "github.com/rancher/wrangler/v3/pkg/summary"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// SummaryCache provides an interface to get a summary/relationships for an object. Implemented by the summaryCache
|
||||
// struct from pkg/summarycache
|
||||
type SummaryCache interface {
|
||||
SummaryAndRelationship(runtime.Object) (*wranglerSummary.SummarizedObject, []summarycache.Relationship)
|
||||
}
|
||||
|
||||
// DefaultFields produces a VirtualTransformFunc through GetTransform() that applies to all k8s types
|
||||
type DefaultFields struct {
|
||||
Cache SummaryCache
|
||||
}
|
||||
|
||||
// GetTransform produces the default transformation func
|
||||
func (d *DefaultFields) GetTransform() cache.TransformFunc {
|
||||
return d.transform
|
||||
}
|
||||
|
||||
// transform implements virtual.VirtualTransformFunc, and adds reserved fields/summary
|
||||
func (d *DefaultFields) transform(obj any) (any, error) {
|
||||
raw, isSignal, err := getUnstructured(obj)
|
||||
if isSignal {
|
||||
return obj, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw = addIDField(raw)
|
||||
raw, err = addSummaryFields(raw, d.Cache)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to add summary fields: %w", err)
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// addSummaryFields adds the virtual fields for object state.
|
||||
func addSummaryFields(raw *unstructured.Unstructured, cache SummaryCache) (*unstructured.Unstructured, error) {
|
||||
s, relationships := cache.SummaryAndRelationship(raw)
|
||||
if s != nil {
|
||||
data.PutValue(raw.Object, map[string]interface{}{
|
||||
"name": s.State,
|
||||
"error": s.Error,
|
||||
"transitioning": s.Transitioning,
|
||||
"message": strings.Join(s.Message, ":"),
|
||||
}, "metadata", "state")
|
||||
|
||||
}
|
||||
var rels []any
|
||||
for _, relationship := range relationships {
|
||||
rel, err := toMap(relationship)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to convert relationship to map: %w", err)
|
||||
}
|
||||
rels = append(rels, rel)
|
||||
}
|
||||
data.PutValue(raw.Object, rels, "metadata", "relationships")
|
||||
|
||||
normalizeConditions(raw)
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// addIDField adds the ID field based on namespace/name, and moves the current id field to _id if present
|
||||
func addIDField(raw *unstructured.Unstructured) *unstructured.Unstructured {
|
||||
objectID := raw.GetName()
|
||||
namespace := raw.GetNamespace()
|
||||
if namespace != "" {
|
||||
objectID = fmt.Sprintf("%s/%s", namespace, objectID)
|
||||
}
|
||||
currentIDValue, ok := raw.Object["id"]
|
||||
if ok {
|
||||
raw.Object["_id"] = currentIDValue
|
||||
}
|
||||
raw.Object["id"] = objectID
|
||||
return raw
|
||||
}
|
||||
|
||||
func normalizeConditions(raw *unstructured.Unstructured) {
|
||||
var (
|
||||
obj data.Object
|
||||
newConditions []any
|
||||
)
|
||||
|
||||
obj = raw.Object
|
||||
for _, condition := range obj.Slice("status", "conditions") {
|
||||
var summary wranglerSummary.Summary
|
||||
for _, summarizer := range wranglerSummary.ConditionSummarizers {
|
||||
summary = summarizer(obj, []wranglerSummary.Condition{{Object: condition}}, summary)
|
||||
}
|
||||
condition.Set("error", summary.Error)
|
||||
condition.Set("transitioning", summary.Transitioning)
|
||||
|
||||
if condition.String("lastUpdateTime") == "" {
|
||||
condition.Set("lastUpdateTime", condition.String("lastTransitionTime"))
|
||||
}
|
||||
// needs to be reconverted back to a map[string]any or we can have encoding problems with unregistered types
|
||||
var mapCondition map[string]any = condition
|
||||
newConditions = append(newConditions, mapCondition)
|
||||
}
|
||||
|
||||
if len(newConditions) > 0 {
|
||||
obj.SetNested(newConditions, "status", "conditions")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user