1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/engine/apicall/apiCall.go
Johann Schley 02c54490bc
Fix default value for apiCall context (#11733)
* chore(deps): bump golang.org/x/crypto from 0.29.0 to 0.30.0 (#11712)

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.29.0 to 0.30.0.
- [Commits](https://github.com/golang/crypto/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Johann Schley <johann.schley@swisscom.com>

* add test for apiCall default value

Signed-off-by: Johann Schley <johann.schley@swisscom.com>

* move fallback to default into fetch function

Signed-off-by: Johann Schley <johann.schley@swisscom.com>

* Update pkg/engine/apicall/apiCall.go

improved log message text

Signed-off-by: Jim Bugwadia <jim@nirmata.com>
Signed-off-by: Johann Schley <johann.schley@swisscom.com>

* Update pkg/engine/apicall/apiCall.go

Signed-off-by: Jim Bugwadia <jim@nirmata.com>
Signed-off-by: Johann Schley <johann.schley@swisscom.com>

* address comments

Signed-off-by: Johann Schley <johann.schley@swisscom.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Johann Schley <johann.schley@swisscom.com>
Signed-off-by: Jim Bugwadia <jim@nirmata.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Johann Schley <johann.schley@swisscom.com>
Co-authored-by: Jim Bugwadia <jim@nirmata.com>
Co-authored-by: shuting <shuting@nirmata.com>
Co-authored-by: Vishal Choudhary <vishal.choudhary@nirmata.com>
2025-01-24 04:54:32 +00:00

140 lines
3.9 KiB
Go

package apicall
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"
)
type apiCall struct {
logger logr.Logger
jp jmespath.Interface
entry kyvernov1.ContextEntry
jsonCtx enginecontext.Interface
executor Executor
}
func New(
logger logr.Logger,
jp jmespath.Interface,
entry kyvernov1.ContextEntry,
jsonCtx enginecontext.Interface,
client ClientInterface,
apiCallConfig APICallConfiguration,
) (*apiCall, error) {
if entry.APICall == nil {
return nil, fmt.Errorf("missing APICall in context entry %v", entry)
}
executor := NewExecutor(logger, entry.Name, client, apiCallConfig)
return &apiCall{
logger: logger,
jp: jp,
entry: entry,
jsonCtx: jsonCtx,
executor: executor,
}, nil
}
func (a *apiCall) FetchAndLoad(ctx context.Context) ([]byte, error) {
data, err := a.Fetch(ctx)
if err != nil {
return nil, err
}
results, err := a.Store(data)
if err != nil {
return nil, err
}
return results, nil
}
func (a *apiCall) Fetch(ctx context.Context) ([]byte, error) {
call, err := variables.SubstituteAllInType(a.logger, a.jsonCtx, a.entry.APICall)
if err != nil {
return nil, fmt.Errorf("failed to substitute variables in context entry %s %s: %v", a.entry.Name, a.entry.APICall.URLPath, err)
}
data, err := a.Execute(ctx, &call.APICall)
if err != nil {
if data == nil && a.entry.APICall.Default != nil {
data = a.entry.APICall.Default.Raw
a.logger.V(4).Info("failed to substitute variable data for APICall, using default value", "default", data, "name", a.entry.Name, "URLPath", a.entry.APICall.URLPath, "error", err)
return data, nil
}
return nil, err
}
return data, nil
}
func (a *apiCall) Store(data []byte) ([]byte, error) {
results, err := a.transformAndStore(data)
if err != nil {
return nil, err
}
return results, nil
}
func (a *apiCall) Execute(ctx context.Context, call *kyvernov1.APICall) ([]byte, error) {
return a.executor.Execute(ctx, call)
}
func (a *apiCall) transformAndStore(jsonData []byte) ([]byte, error) {
if a.entry.APICall.Default != nil {
if string(jsonData) == string(a.entry.APICall.Default.Raw) {
err := a.jsonCtx.AddContextEntry(a.entry.Name, jsonData)
if err != nil {
return nil, fmt.Errorf("failed to add resource data to context entry %s: %w", a.entry.Name, err)
}
return jsonData, nil
}
}
if a.entry.APICall.JMESPath == "" {
err := a.jsonCtx.AddContextEntry(a.entry.Name, jsonData)
if err != nil {
return nil, fmt.Errorf("failed to add resource data to context entry %s: %w", a.entry.Name, err)
}
return jsonData, nil
}
path, err := variables.SubstituteAll(a.logger, a.jsonCtx, a.entry.APICall.JMESPath)
if err != nil {
return nil, fmt.Errorf("failed to substitute variables in context entry %s JMESPath %s: %w", a.entry.Name, a.entry.APICall.JMESPath, err)
}
results, err := a.applyJMESPathJSON(path.(string), jsonData)
if err != nil {
return nil, fmt.Errorf("failed to apply JMESPath %s for context entry %s: %w", path, a.entry.Name, err)
}
contextData, err := json.Marshal(results)
if err != nil {
return nil, fmt.Errorf("failed to marshall APICall data for context entry %s: %w", a.entry.Name, err)
}
err = a.jsonCtx.AddContextEntry(a.entry.Name, contextData)
if err != nil {
return nil, fmt.Errorf("failed to add APICall results for context entry %s: %w", a.entry.Name, err)
}
a.logger.V(4).Info("added context data", "name", a.entry.Name, "len", len(contextData))
return contextData, nil
}
func (a *apiCall) 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)
}