1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/engine/context/loaders/globalcontext.go

148 lines
4.2 KiB
Go
Raw Normal View History

package loaders
import (
"context"
"encoding/json"
"fmt"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/globalcontext/store"
)
type Store interface {
Get(key string) (store.Entry, bool)
}
type gctxLoader struct {
ctx context.Context //nolint:containedctx
logger logr.Logger
entry kyvernov1.ContextEntry
enginectx enginecontext.Interface
jp jmespath.Interface
gctxStore Store
data []byte
}
func NewGCTXLoader(
ctx context.Context,
logger logr.Logger,
entry kyvernov1.ContextEntry,
enginectx enginecontext.Interface,
jp jmespath.Interface,
gctxStore Store,
) enginecontext.Loader {
return &gctxLoader{
ctx: ctx,
logger: logger,
entry: entry,
enginectx: enginectx,
jp: jp,
gctxStore: gctxStore,
}
}
func (g *gctxLoader) HasLoaded() bool {
data, ok := g.gctxStore.Get(g.entry.Name)
if !ok {
g.logger.Error(fmt.Errorf("failed to get data from global context store"), "failed to get data from global context store")
return false
}
if data == nil {
return false
}
return true
}
func (g *gctxLoader) LoadData() error {
contextData, err := g.loadGctxData()
if err != nil {
g.logger.Error(err, "failed to marshal APICall data for context entry")
return fmt.Errorf("failed to marshal APICall data for context entry %s: %w", g.entry.Name, err)
}
err = g.enginectx.AddContextEntry(g.entry.Name, contextData)
if err != nil {
g.logger.Error(err, "failed to add resource cache results for context entry")
return fmt.Errorf("failed to add resource cache results for context entry %s: %w", g.entry.Name, err)
}
g.logger.V(6).Info("added context data", "name", g.entry.Name, "contextData", contextData)
g.data = contextData
return nil
}
func (g *gctxLoader) loadGctxData() ([]byte, error) {
var data interface{}
var err error
if g.entry.GlobalReference == nil {
g.logger.Error(err, "context entry does not have resource cache")
return nil, fmt.Errorf("resource cache not found")
}
rc, err := variables.SubstituteAllInType(g.logger, g.enginectx, g.entry.GlobalReference)
if err != nil {
return nil, err
}
g.logger.V(6).Info("variables substituted", "resourcecache", rc)
storeEntry, ok := g.gctxStore.Get(rc.Name)
if !ok {
err := fmt.Errorf("failed to fetch entry key=%s", rc.Name)
g.logger.Error(err, "")
return nil, err
}
data, err = storeEntry.Get()
if err != nil {
g.logger.Error(err, "failed to fetch data from entry")
return nil, err
}
var jsonData []byte
if _, ok := data.([]byte); ok {
jsonData = data.([]byte)
} else {
jsonData, err = json.Marshal(data)
if err != nil {
return nil, err
}
}
g.logger.V(6).Info("fetched json data", "name", g.entry.Name, "jsondata", jsonData)
if g.entry.GlobalReference.JMESPath == "" {
err := g.enginectx.AddContextEntry(g.entry.Name, jsonData)
if err != nil {
g.logger.Error(err, "failed to add resource data to context entry")
return nil, fmt.Errorf("failed to add resource data to context entry %s: %w", g.entry.Name, err)
}
return jsonData, nil
}
path, err := variables.SubstituteAll(g.logger, g.enginectx, rc.JMESPath)
if err != nil {
g.logger.Error(err, "failed to substitute variables in context entry")
return nil, fmt.Errorf("failed to substitute variables in context entry %s JMESPath %s: %w", g.entry.Name, rc.JMESPath, err)
}
results, err := g.applyJMESPathJSON(path.(string), jsonData)
if err != nil {
g.logger.Error(err, "failed to apply JMESPath for context entry")
return nil, fmt.Errorf("failed to apply JMESPath %s for context entry %s: %w", path, g.entry.Name, err)
}
g.logger.V(6).Info("applied jmespath expression", "name", g.entry.Name, "results", results)
return json.Marshal(results)
}
func (a *gctxLoader) applyJMESPathJSON(jmesPath string, jsonData []byte) (interface{}, error) {
var data interface{}
err := json.Unmarshal(jsonData, &data)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %s, error: %w", string(jsonData), err)
}
return a.jp.Search(jmesPath, data)
}