Skip to content

Commit 2b5746e

Browse files
kvapsclaude
andauthored
fix(lookup): fix metadata extraction and error handling (#107)
- Extract metadata directly from resource methods instead of YAML round-trip which returned yaml.Node structure instead of actual data - Ignore NotFound and PermissionDenied errors in lookup callback, allowing templates to use fallback logic when resources are unavailable - Change items from map to slice for proper range iteration in templates This fixes lookup functionality in maintenance mode and Talos 1.12+. Signed-off-by: Andrei Kvapil <kvapss@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent c558560 commit 2b5746e

1 file changed

Lines changed: 24 additions & 14 deletions

File tree

pkg/engine/engine.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import (
1010
"path/filepath"
1111
"reflect"
1212
"regexp"
13-
"strconv"
1413
"strings"
1514
"unsafe"
1615

16+
"google.golang.org/grpc/codes"
17+
"google.golang.org/grpc/status"
1718
"gopkg.in/yaml.v3"
1819

1920
"github.com/cosi-project/runtime/pkg/resource"
@@ -562,20 +563,21 @@ func readUnexportedField(field reflect.Value) any {
562563

563564
// builds resource with metadata, spec and stringSpec fields
564565
func extractResourceData(r resource.Resource) (map[string]interface{}, error) {
565-
// extract metadata
566-
o, err := resource.MarshalYAML(r)
567-
if err != nil {
568-
return nil, fmt.Errorf("failed to marshal resource to YAML: %w", err)
569-
}
570-
m, err := yaml.Marshal(o)
571-
if err != nil {
572-
return nil, fmt.Errorf("failed to marshal metadata to YAML: %w", err)
573-
}
574566
res := make(map[string]interface{})
575-
if err := yaml.Unmarshal(m, &res); err != nil {
576-
return nil, fmt.Errorf("failed to unmarshal metadata: %w", err)
567+
568+
// Extract metadata directly from resource methods
569+
md := r.Metadata()
570+
metadata := map[string]interface{}{
571+
"namespace": string(md.Namespace()),
572+
"type": string(md.Type()),
573+
"id": string(md.ID()),
574+
"version": md.Version().String(),
575+
"phase": md.Phase().String(),
576+
"owner": string(md.Owner()),
577577
}
578578

579+
res["metadata"] = metadata
580+
579581
// extract spec
580582
val := reflect.ValueOf(r.Spec())
581583
if val.Kind() == reflect.Ptr {
@@ -606,6 +608,13 @@ func newLookupFunction(ctx context.Context, c *client.Client) func(resource stri
606608

607609
callbackResource := func(parentCtx context.Context, hostname string, r resource.Resource, callError error) error {
608610
if callError != nil {
611+
// Ignore NotFound and PermissionDenied errors - resource doesn't exist or is not accessible
612+
errCode := status.Code(callError)
613+
errStr := callError.Error()
614+
if errCode == codes.NotFound || errCode == codes.PermissionDenied ||
615+
strings.Contains(errStr, "code = NotFound") || strings.Contains(errStr, "code = PermissionDenied") {
616+
return nil
617+
}
609618
multiErr = multierror.Append(multiErr, callError)
610619
return nil
611620
}
@@ -636,9 +645,10 @@ func newLookupFunction(ctx context.Context, c *client.Client) func(resource stri
636645
if id != "" && len(resources) == 1 {
637646
return resources[0], nil
638647
}
639-
items := map[string]interface{}{}
648+
// Return items as a slice for proper range iteration in templates
649+
items := make([]interface{}, len(resources))
640650
for i, res := range resources {
641-
items["_"+strconv.Itoa(i)] = res
651+
items[i] = res
642652
}
643653
return map[string]interface{}{
644654
"apiVersion": "v1",

0 commit comments

Comments
 (0)