Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions internal/adapter/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package adapter
import (
"maps"
"sort"
"strings"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/external-dns/endpoint"
Expand All @@ -27,6 +28,7 @@ import (
v1alpha2 "github.com/golgoth31/sreportal/api/v1alpha2"
"github.com/golgoth31/sreportal/internal/config"
domaindns "github.com/golgoth31/sreportal/internal/domain/dns"
"github.com/golgoth31/sreportal/internal/log"
)

const (
Expand Down Expand Up @@ -269,11 +271,30 @@ func extractNamespace(resource string) string {
return ref.Namespace()
}

// originRefFromLabel parses an external-dns resource label into an OriginResourceRef.
// Returns nil when the label is absent or malformed.
func originRefFromLabel(raw string) *sreportalv1alpha1.OriginResourceRef {
// parseOriginLabel parses the external-dns "resource" label
// (kind/namespace/name). An empty label is expected (the endpoint has no
// originating resource) and returns ok=false silently. A non-empty but
// unparsable label is an anomaly — it would otherwise drop the origin with no
// trace (the FQDN card shows no source) — so it is logged at warn level.
func parseOriginLabel(raw string) (domaindns.ResourceRef, bool) {
if strings.TrimSpace(raw) == "" {
return domaindns.ResourceRef{}, false
}
ref, err := domaindns.ParseResourceRef(raw)
if err != nil || ref.IsZero() {
log.Default().WithName("adapter.endpoint").Warn(
"ignoring malformed external-dns resource label",
"resource", raw, "err", err)
return domaindns.ResourceRef{}, false
}
return ref, true
}

// originRefFromLabel parses an external-dns resource label into an OriginResourceRef.
// Returns nil when the label is absent or malformed (malformed is logged).
func originRefFromLabel(raw string) *sreportalv1alpha1.OriginResourceRef {
ref, ok := parseOriginLabel(raw)
if !ok {
return nil
}
return &sreportalv1alpha1.OriginResourceRef{
Expand Down Expand Up @@ -365,6 +386,10 @@ func EndpointStatusToGroups(endpoints []sreportalv1alpha1.EndpointStatus, mappin
}

ns := extractNamespace(ep.Labels[endpoint.ResourceLabelKey])
// Parse once per endpoint (not per group): the label is identical across
// this endpoint's groups, so this avoids re-parsing and, for a malformed
// label, avoids logging once per group.
originRef := originRefFromLabel(ep.Labels[endpoint.ResourceLabelKey])
groupNames := strategy.Resolve(ep.Labels, ns)

for _, groupName := range groupNames {
Expand Down Expand Up @@ -392,7 +417,7 @@ func EndpointStatusToGroups(endpoints []sreportalv1alpha1.EndpointStatus, mappin
Targets: ep.Targets,
SyncStatus: ep.SyncStatus,
LastSeen: ep.LastSeen,
OriginRef: originRefFromLabel(ep.Labels[endpoint.ResourceLabelKey]),
OriginRef: originRef,
})
}
}
Expand Down Expand Up @@ -553,8 +578,8 @@ func strategyFromV2Spec(mapping *v1alpha2.GroupMappingSpec) domaindns.GroupMappi
// originRefV2FromLabel parses an external-dns resource label into a v1alpha2.OriginResourceRef.
// Returns nil when the label is absent or malformed.
func originRefV2FromLabel(raw string) *v1alpha2.OriginResourceRef {
ref, err := domaindns.ParseResourceRef(raw)
if err != nil || ref.IsZero() {
ref, ok := parseOriginLabel(raw)
if !ok {
return nil
}
return &v1alpha2.OriginResourceRef{
Expand Down Expand Up @@ -596,6 +621,8 @@ func EndpointStatusToGroupsV2(endpoints []v1alpha2.EndpointStatus, mapping *v1al
}

ns := extractNamespace(ep.Labels[endpoint.ResourceLabelKey])
// Parse once per endpoint (not per group): see EndpointStatusToGroups.
originRef := originRefV2FromLabel(ep.Labels[endpoint.ResourceLabelKey])
groupNames := strategy.Resolve(ep.Labels, ns)

for _, groupName := range groupNames {
Expand All @@ -622,7 +649,7 @@ func EndpointStatusToGroupsV2(endpoints []v1alpha2.EndpointStatus, mapping *v1al
Targets: ep.Targets,
SyncStatus: ep.SyncStatus,
LastSeen: ep.LastSeen,
OriginRef: originRefV2FromLabel(ep.Labels[endpoint.ResourceLabelKey]),
OriginRef: originRef,
})
}
}
Expand Down
71 changes: 71 additions & 0 deletions internal/adapter/originlabel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package adapter

import (
"bytes"
"log/slog"
"strings"
"testing"
)

// captureSlog redirects slog.Default() to buf for the duration of the test.
func captureSlog(t *testing.T, level slog.Level) *bytes.Buffer {
t.Helper()
buf := &bytes.Buffer{}
prev := slog.Default()
slog.SetDefault(slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{Level: level})))
t.Cleanup(func() { slog.SetDefault(prev) })
return buf
}

func TestOriginRefV2FromLabel_Valid(t *testing.T) {
got := originRefV2FromLabel("service/ns/name")
if got == nil || got.Kind != "service" || got.Namespace != "ns" || got.Name != "name" {
t.Fatalf("unexpected ref: %+v", got)
}
}

func TestOriginRefV2FromLabel_EmptyIsSilent(t *testing.T) {
buf := captureSlog(t, slog.LevelDebug)
if got := originRefV2FromLabel(""); got != nil {
t.Fatalf("want nil for empty label, got %+v", got)
}
if buf.Len() != 0 {
t.Fatalf("empty label must not log, got: %q", buf.String())
}
}

func TestOriginRefV2FromLabel_MalformedLogsWarn(t *testing.T) {
buf := captureSlog(t, slog.LevelWarn)
if got := originRefV2FromLabel("not-a-valid-ref"); got != nil {
t.Fatalf("want nil for malformed label, got %+v", got)
}
out := buf.String()
if !strings.Contains(out, "level=WARN") ||
!strings.Contains(out, "malformed external-dns resource label") {
t.Fatalf("expected WARN log for malformed label, got: %q", out)
}
}

// origin v1 shares parseOriginLabel; one case is enough to cover the v1 wrapper.
func TestOriginRefFromLabel_MalformedReturnsNil(t *testing.T) {
_ = captureSlog(t, slog.LevelWarn)
if got := originRefFromLabel("bad"); got != nil {
t.Fatalf("want nil for malformed label, got %+v", got)
}
}