1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

fix: context in api call (#6885)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-04-12 23:52:01 +02:00 committed by GitHub
parent 2d64cdf6e2
commit f7f3bc79d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 39 deletions

View file

@ -90,11 +90,11 @@ func LoadImageData(ctx context.Context, rclient registryclient.Client, logger lo
}
func LoadAPIData(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, client dclient.Interface) error {
executor, err := apicall.New(ctx, entry, enginectx, client, logger)
executor, err := apicall.New(logger, entry, enginectx, client)
if err != nil {
return fmt.Errorf("failed to initialize APICall: %w", err)
}
if _, err := executor.Execute(); err != nil {
if _, err := executor.Execute(ctx); err != nil {
return fmt.Errorf("failed to execute APICall: %w", err)
}
return nil

View file

@ -2,7 +2,7 @@ package apicall
import (
"bytes"
goctx "context"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
@ -14,40 +14,42 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/engine/context"
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 {
log logr.Logger
logger logr.Logger
entry kyvernov1.ContextEntry
ctx goctx.Context
jsonCtx context.Interface
jsonCtx enginecontext.Interface
client dclient.Interface
}
func New(ctx goctx.Context, entry kyvernov1.ContextEntry, jsonCtx context.Interface, client dclient.Interface, log logr.Logger) (*apiCall, error) {
func New(
log logr.Logger,
entry kyvernov1.ContextEntry,
jsonCtx enginecontext.Interface,
client dclient.Interface,
) (*apiCall, error) {
if entry.APICall == nil {
return nil, fmt.Errorf("missing APICall in context entry %v", entry)
}
return &apiCall{
ctx: ctx,
entry: entry,
jsonCtx: jsonCtx,
client: client,
log: log,
logger: log,
}, nil
}
func (a *apiCall) Execute() ([]byte, error) {
call, err := variables.SubstituteAllInType(a.log, a.jsonCtx, a.entry.APICall)
func (a *apiCall) Execute(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(call)
data, err := a.execute(ctx, call)
if err != nil {
return nil, err
}
@ -60,25 +62,25 @@ func (a *apiCall) Execute() ([]byte, error) {
return result, nil
}
func (a *apiCall) execute(call *kyvernov1.APICall) ([]byte, error) {
func (a *apiCall) execute(ctx context.Context, call *kyvernov1.APICall) ([]byte, error) {
if call.URLPath != "" {
return a.executeK8sAPICall(call.URLPath)
return a.executeK8sAPICall(ctx, call.URLPath)
}
return a.executeServiceCall(call.Service)
return a.executeServiceCall(ctx, call.Service)
}
func (a *apiCall) executeK8sAPICall(path string) ([]byte, error) {
jsonData, err := a.client.RawAbsPath(a.ctx, path)
func (a *apiCall) executeK8sAPICall(ctx context.Context, path string) ([]byte, error) {
jsonData, err := a.client.RawAbsPath(ctx, path)
if err != nil {
return nil, fmt.Errorf("failed to get resource with raw url\n: %s: %v", path, err)
}
a.log.V(4).Info("executed APICall", "name", a.entry.Name, "len", len(jsonData))
a.logger.V(4).Info("executed APICall", "name", a.entry.Name, "len", len(jsonData))
return jsonData, nil
}
func (a *apiCall) executeServiceCall(service *kyvernov1.ServiceCall) ([]byte, error) {
func (a *apiCall) executeServiceCall(ctx context.Context, service *kyvernov1.ServiceCall) ([]byte, error) {
if service == nil {
return nil, fmt.Errorf("missing service for APICall %s", a.entry.Name)
}
@ -88,7 +90,7 @@ func (a *apiCall) executeServiceCall(service *kyvernov1.ServiceCall) ([]byte, er
return nil, err
}
req, err := a.buildHTTPRequest(service)
req, err := a.buildHTTPRequest(ctx, service)
if err != nil {
return nil, fmt.Errorf("failed to build HTTP request for APICall %s: %w", a.entry.Name, err)
}
@ -113,11 +115,11 @@ func (a *apiCall) executeServiceCall(service *kyvernov1.ServiceCall) ([]byte, er
return nil, fmt.Errorf("failed to read data from APICall %s: %w", a.entry.Name, err)
}
a.log.Info("executed service APICall", "name", a.entry.Name, "len", len(body))
a.logger.Info("executed service APICall", "name", a.entry.Name, "len", len(body))
return body, nil
}
func (a *apiCall) buildHTTPRequest(service *kyvernov1.ServiceCall) (req *http.Request, err error) {
func (a *apiCall) buildHTTPRequest(ctx context.Context, service *kyvernov1.ServiceCall) (req *http.Request, err error) {
token := a.getToken()
defer func() {
if token != "" && req != nil {
@ -126,7 +128,7 @@ func (a *apiCall) buildHTTPRequest(service *kyvernov1.ServiceCall) (req *http.Re
}()
if service.Method == "GET" {
req, err = http.NewRequest("GET", service.URL, nil)
req, err = http.NewRequestWithContext(ctx, "GET", service.URL, nil)
return
}
@ -147,7 +149,7 @@ func (a *apiCall) getToken() string {
fileName := "/var/run/secrets/kubernetes.io/serviceaccount/token"
b, err := os.ReadFile(fileName)
if err != nil {
a.log.Info("failed to read service account token", "path", fileName)
a.logger.Info("failed to read service account token", "path", fileName)
return ""
}
@ -198,7 +200,7 @@ func (a *apiCall) transformAndStore(jsonData []byte) ([]byte, error) {
return jsonData, nil
}
path, err := variables.SubstituteAll(a.log, a.jsonCtx, a.entry.APICall.JMESPath)
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)
}
@ -218,7 +220,7 @@ func (a *apiCall) transformAndStore(jsonData []byte) ([]byte, error) {
return nil, fmt.Errorf("failed to add APICall results for context entry %s: %w", a.entry.Name, err)
}
a.log.V(4).Info("added context data", "name", a.entry.Name, "len", len(contextData))
a.logger.V(4).Info("added context data", "name", a.entry.Name, "len", len(contextData))
return contextData, nil
}

View file

@ -40,7 +40,7 @@ func Test_serviceGetRequest(t *testing.T) {
entry := kyvernov1.ContextEntry{}
ctx := enginecontext.NewContext()
_, err := New(context.TODO(), entry, ctx, nil, logr.Discard())
_, err := New(logr.Discard(), entry, ctx, nil)
assert.ErrorContains(t, err, "missing APICall")
entry.Name = "test"
@ -50,22 +50,22 @@ func Test_serviceGetRequest(t *testing.T) {
},
}
call, err := New(context.TODO(), entry, ctx, nil, logr.Discard())
call, err := New(logr.Discard(), entry, ctx, nil)
assert.NilError(t, err)
_, err = call.Execute()
_, err = call.Execute(context.TODO())
assert.ErrorContains(t, err, "invalid request type")
entry.APICall.Service.Method = "GET"
call, err = New(context.TODO(), entry, ctx, nil, logr.Discard())
call, err = New(logr.Discard(), entry, ctx, nil)
assert.NilError(t, err)
_, err = call.Execute()
_, err = call.Execute(context.TODO())
assert.ErrorContains(t, err, "HTTP 404")
entry.APICall.Service.URL = s.URL + "/resource"
call, err = New(context.TODO(), entry, ctx, nil, logr.Discard())
call, err = New(logr.Discard(), entry, ctx, nil)
assert.NilError(t, err)
data, err := call.Execute()
data, err := call.Execute(context.TODO())
assert.NilError(t, err)
assert.Assert(t, data != nil, "nil data")
assert.Equal(t, string(serverResponse), string(data))
@ -87,9 +87,9 @@ func Test_servicePostRequest(t *testing.T) {
}
ctx := enginecontext.NewContext()
call, err := New(context.TODO(), entry, ctx, nil, logr.Discard())
call, err := New(logr.Discard(), entry, ctx, nil)
assert.NilError(t, err)
data, err := call.Execute()
data, err := call.Execute(context.TODO())
assert.NilError(t, err)
assert.Equal(t, "{}\n", string(data))
@ -135,9 +135,9 @@ func Test_servicePostRequest(t *testing.T) {
},
}
call, err = New(context.TODO(), entry, ctx, nil, logr.Discard())
call, err = New(logr.Discard(), entry, ctx, nil)
assert.NilError(t, err)
data, err = call.Execute()
data, err = call.Execute(context.TODO())
assert.NilError(t, err)
expectedResults := `{"images":["https://ghcr.io/tomcat/tomcat:9","https://ghcr.io/vault/vault:v3","https://ghcr.io/busybox/busybox:latest"]}`