1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00
kyverno/pkg/engine/context/evaluate.go
Jim Bugwadia 696c7e924b
lazy loading of context vars (#7071)
* lazy loading of context vars

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* gofumpt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* add kuttl tests

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

---------

Signed-off-by: Jim Bugwadia <jim@nirmata.com>
2023-05-05 20:35:47 -04:00

83 lines
2.1 KiB
Go

package context
import (
"encoding/json"
"fmt"
"strings"
datautils "github.com/kyverno/kyverno/pkg/utils/data"
)
// Query the JSON context with JMESPATH search path
func (ctx *context) Query(query string) (interface{}, error) {
if err := ctx.loadDeferred(query); err != nil {
return nil, err
}
query = strings.TrimSpace(query)
if query == "" {
return nil, fmt.Errorf("invalid query (nil)")
}
// compile the query
queryPath, err := ctx.jp.Query(query)
if err != nil {
logger.Error(err, "incorrect query", "query", query)
return nil, fmt.Errorf("incorrect query %s: %v", query, err)
}
// search
ctx.mutex.RLock()
defer ctx.mutex.RUnlock()
var data interface{}
if err := json.Unmarshal(ctx.jsonRaw, &data); err != nil {
return nil, fmt.Errorf("failed to unmarshal context: %w", err)
}
result, err := queryPath.Search(data)
if err != nil {
return nil, fmt.Errorf("JMESPath query failed: %w", err)
}
return result, nil
}
func (ctx *context) loadDeferred(query string) error {
loaders := ctx.getMatchingLoaders(query)
for _, l := range loaders {
if err := l(); err != nil {
return err
}
}
return nil
}
func (ctx *context) getMatchingLoaders(query string) []DeferredLoader {
ctx.deferred.mutex.Lock()
defer ctx.deferred.mutex.Unlock()
var matchingLoaders []DeferredLoader
for name, deferredLoader := range ctx.deferred.loaders {
if strings.Contains(query, name) {
matchingLoaders = append(matchingLoaders, deferredLoader)
delete(ctx.deferred.loaders, name)
}
}
return matchingLoaders
}
func (ctx *context) HasChanged(jmespath string) (bool, error) {
objData, err := ctx.Query("request.object." + jmespath)
if err != nil {
return false, fmt.Errorf("failed to query request.object: %w", err)
}
if objData == nil {
return false, fmt.Errorf("request.object.%s not found", jmespath)
}
oldObjData, err := ctx.Query("request.oldObject." + jmespath)
if err != nil {
return false, fmt.Errorf("failed to query request.object: %w", err)
}
if oldObjData == nil {
return false, fmt.Errorf("request.oldObject.%s not found", jmespath)
}
return !datautils.DeepEqual(objData, oldObjData), nil
}