fix(engine): log debug warning when lookup returns no object

Signed-off-by: texasich <texasich@users.noreply.github.com>
pull/32124/head
texasich 5 months ago
parent b2786f15f2
commit 2220a0ba58

@ -17,8 +17,10 @@ limitations under the License.
package engine package engine
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"log/slog"
"path" "path"
"strings" "strings"
"sync" "sync"
@ -393,6 +395,51 @@ func TestRenderWithClientProvider(t *testing.T) {
} }
} }
func TestLookupLogsDebugWhenObjectNotFound(t *testing.T) {
provider := &testClientProvider{
t: t,
scheme: map[string]kindProps{
"v1/Namespace": {
gvr: schema.GroupVersionResource{
Version: "v1",
Resource: "namespaces",
},
},
},
objects: []runtime.Object{
makeUnstructured("v1", "Namespace", "default", ""),
},
}
originalLogger := slog.Default()
logBuffer := &bytes.Buffer{}
slog.SetDefault(slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug})))
t.Cleanup(func() {
slog.SetDefault(originalLogger)
})
lookup := newLookupFunction(provider)
_, err := lookup("v1", "Namespace", "", "absent")
if err != nil {
t.Fatalf("expected no error when lookup object is missing: %v", err)
}
logOutput := logBuffer.String()
if !strings.Contains(logOutput, "lookup returned no object") {
t.Fatalf("expected debug log for missing lookup object, got: %q", logOutput)
}
logBuffer.Reset()
_, err = lookup("v1", "Namespace", "", "default")
if err != nil {
t.Fatalf("expected no error when lookup object exists: %v", err)
}
if strings.Contains(logBuffer.String(), "lookup returned no object") {
t.Fatalf("did not expect missing-object debug log for existing lookup object, got: %q", logBuffer.String())
}
}
func TestRenderWithClientProvider_error(t *testing.T) { func TestRenderWithClientProvider_error(t *testing.T) {
c := &chart.Chart{ c := &chart.Chart{
Metadata: &chart.Metadata{ Metadata: &chart.Metadata{

@ -21,6 +21,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"log/slog"
"maps" "maps"
"math" "math"
"reflect" "reflect"
@ -89,7 +90,8 @@ func funcMap() template.FuncMap {
"required": func(string, any) (any, error) { return "not implemented", nil }, "required": func(string, any) (any, error) { return "not implemented", nil },
// Provide a placeholder for the "lookup" function, which requires a kubernetes // Provide a placeholder for the "lookup" function, which requires a kubernetes
// connection. // connection.
"lookup": func(string, string, string, string) (map[string]any, error) { "lookup": func(apiVersion, kind, namespace, name string) (map[string]any, error) {
slog.Debug("lookup skipped: no Kubernetes client available", "apiVersion", apiVersion, "kind", kind, "namespace", namespace, "name", name)
return map[string]any{}, nil return map[string]any{}, nil
}, },
} }

@ -17,6 +17,8 @@ limitations under the License.
package engine package engine
import ( import (
"bytes"
"log/slog"
"math" "math"
"strings" "strings"
"testing" "testing"
@ -195,6 +197,26 @@ keyInElement1 = "valueInElement1"`,
} }
} }
func TestLookupPlaceholderLogsDebug(t *testing.T) {
originalLogger := slog.Default()
logBuffer := &bytes.Buffer{}
slog.SetDefault(slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug})))
t.Cleanup(func() {
slog.SetDefault(originalLogger)
})
var output strings.Builder
err := template.Must(template.New("test").Funcs(funcMap()).Parse(`{{ lookup "v1" "Namespace" "" "missing" }}`)).Execute(&output, nil)
require.NoError(t, err)
assert.Equal(t, "map[]", output.String())
logOutput := logBuffer.String()
assert.Contains(t, logOutput, "lookup skipped: no Kubernetes client available")
assert.Contains(t, logOutput, "apiVersion=v1")
assert.Contains(t, logOutput, "kind=Namespace")
assert.Contains(t, logOutput, "name=missing")
}
func TestDurationHelpers(t *testing.T) { func TestDurationHelpers(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

@ -73,6 +73,7 @@ func newLookupFunction(clientProvider ClientProvider) lookupFunc {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
// Just return an empty interface when the object was not found. // Just return an empty interface when the object was not found.
// That way, users can use `if not (lookup ...)` in their templates. // That way, users can use `if not (lookup ...)` in their templates.
slog.Debug("lookup returned no object", "apiVersion", apiversion, "kind", kind, "namespace", namespace, "name", name)
return map[string]any{}, nil return map[string]any{}, nil
} }
return map[string]any{}, err return map[string]any{}, err
@ -85,6 +86,7 @@ func newLookupFunction(clientProvider ClientProvider) lookupFunc {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
// Just return an empty interface when the object was not found. // Just return an empty interface when the object was not found.
// That way, users can use `if not (lookup ...)` in their templates. // That way, users can use `if not (lookup ...)` in their templates.
slog.Debug("lookup returned no objects", "apiVersion", apiversion, "kind", kind, "namespace", namespace)
return map[string]any{}, nil return map[string]any{}, nil
} }
return map[string]any{}, err return map[string]any{}, err

Loading…
Cancel
Save