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
9 changes: 7 additions & 2 deletions controller/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,13 @@ func buildSource(ctx context.Context, cfg *externaldns.Config) (source.Source, e
// Combine multiple sources into a single, deduplicated source.
combinedSource := wrappers.NewDedupSource(wrappers.NewMultiSource(sources, sourceCfg.DefaultTargets, sourceCfg.ForceDefaultTargets))
cfg.AddSourceWrapper("dedup")
combinedSource = wrappers.NewNAT64Source(combinedSource, cfg.NAT64Networks)
cfg.AddSourceWrapper("nat64")
if len(cfg.NAT64Networks) > 0 {
combinedSource, err = wrappers.NewNAT64Source(combinedSource, cfg.NAT64Networks)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, other wrappers do not return errors. It would be better to define a common interface for all wrappers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean all wrapper's constructors should also return an error?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. If one returns an error, I think all should return an error. So we have some level of consistency.

if err != nil {
return nil, fmt.Errorf("failed to create NAT64 source wrapper: %w", err)
}
cfg.AddSourceWrapper("nat64")
}
// Filter targets
targetFilter := endpoint.NewTargetNetFilterWithExclusions(cfg.TargetNetFilter, cfg.ExcludeTargetNets)
if targetFilter.IsEnabled() {
Expand Down
15 changes: 13 additions & 2 deletions controller/execute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,14 +454,25 @@ func TestBuildSourceWithWrappers(t *testing.T) {
},
},
{
name: "configuration without target filter wrapper",
name: "configuration with nat64 networks",
cfg: &externaldns.Config{
APIServerURL: svr.URL,
Sources: []string{"fake"},
NAT64Networks: []string{"2001:db8::/96"},
},
asserts: func(t *testing.T, cfg *externaldns.Config) {
assert.True(t, cfg.IsSourceWrapperInstrumented("nat64"))
},
},
{
name: "default configuration",
cfg: &externaldns.Config{
APIServerURL: svr.URL,
Sources: []string{"fake"},
},
asserts: func(t *testing.T, cfg *externaldns.Config) {
assert.True(t, cfg.IsSourceWrapperInstrumented("dedup"))
assert.True(t, cfg.IsSourceWrapperInstrumented("nat64"))
assert.False(t, cfg.IsSourceWrapperInstrumented("nat64"))
assert.False(t, cfg.IsSourceWrapperInstrumented("target-filter"))
},
},
Expand Down
20 changes: 10 additions & 10 deletions source/wrappers/nat64source.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,13 @@ import (
// nat64Source is a Source that adds A endpoints for AAAA records including an NAT64 address.
type nat64Source struct {
source source.Source
nat64Prefixes []string
nat64Prefixes []netip.Prefix
}

// NewNAT64Source creates a new nat64Source wrapping the provided Source.
func NewNAT64Source(source source.Source, nat64Prefixes []string) source.Source {
return &nat64Source{source: source, nat64Prefixes: nat64Prefixes}
}

// Endpoints collects endpoints from its wrapped source and returns them without duplicates.
func (s *nat64Source) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
log.Debug("nat64Source: collecting endpoints and processing NAT64 translation")
func NewNAT64Source(source source.Source, nat64Prefixes []string) (source.Source, error) {
parsedNAT64Prefixes := make([]netip.Prefix, 0)
for _, prefix := range s.nat64Prefixes {
for _, prefix := range nat64Prefixes {
pPrefix, err := netip.ParsePrefix(prefix)
if err != nil {
return nil, err
Expand All @@ -53,6 +47,12 @@ func (s *nat64Source) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, erro
}
parsedNAT64Prefixes = append(parsedNAT64Prefixes, pPrefix)
}
return &nat64Source{source: source, nat64Prefixes: parsedNAT64Prefixes}, nil
}

// Endpoints collects endpoints from its wrapped source and returns them without duplicates.
func (s *nat64Source) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
log.Debug("nat64Source: collecting endpoints and processing NAT64 translation")

additionalEndpoints := []*endpoint.Endpoint{}

Expand All @@ -76,7 +76,7 @@ func (s *nat64Source) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, erro

var sPrefix *netip.Prefix

for _, cPrefix := range parsedNAT64Prefixes {
for _, cPrefix := range s.nat64Prefixes {
if cPrefix.Contains(ip) {
sPrefix = &cPrefix
}
Expand Down
79 changes: 74 additions & 5 deletions source/wrappers/nat64source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ package wrappers

import (
"context"
"net/netip"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/internal/testutils"
"sigs.k8s.io/external-dns/source"
Expand Down Expand Up @@ -74,12 +77,11 @@ func testNat64Source(t *testing.T) {
mockSource.On("Endpoints").Return(tc.endpoints, nil)

// Create our object under test and get the endpoints.
source := NewNAT64Source(mockSource, []string{"2001:DB8::/96"})
source, err := NewNAT64Source(mockSource, []string{"2001:DB8::/96"})
require.NoError(t, err)

endpoints, err := source.Endpoints(context.Background())
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

// Validate returned endpoints against desired endpoints.
validateEndpoints(t, endpoints, tc.expected)
Expand Down Expand Up @@ -112,10 +114,77 @@ func TestNat64Source_AddEventHandler(t *testing.T) {
t.Run(tt.title, func(t *testing.T) {
mockSource := testutils.NewMockSource()

src := NewNAT64Source(mockSource, tt.input)
src, err := NewNAT64Source(mockSource, tt.input)
require.NoError(t, err)

src.AddEventHandler(t.Context(), func() {})

mockSource.AssertNumberOfCalls(t, "AddEventHandler", tt.times)
})
}
}

func TestNewNAT64Source(t *testing.T) {
type args struct {
source source.Source
nat64Prefixes []string
}
tests := []struct {
name string
args args
want source.Source
wantErr bool
}{
{
name: "empty NAT64 prefixes should succeed",
args: args{
source: &testutils.MockSource{},
nat64Prefixes: []string{},
},
want: &nat64Source{source: &testutils.MockSource{}, nat64Prefixes: []netip.Prefix{}},
},
{
name: "multiple valid NAT64 prefixes should succeed",
args: args{
source: &testutils.MockSource{},
nat64Prefixes: []string{"2001:db8::/96", "64:ff9b::/96"},
},
want: &nat64Source{source: &testutils.MockSource{}, nat64Prefixes: []netip.Prefix{netip.MustParsePrefix("2001:db8::/96"), netip.MustParsePrefix("64:ff9b::/96")}},
},
{
name: "invalid NAT64 prefix should fail",
args: args{
source: &testutils.MockSource{},
nat64Prefixes: []string{"invalid-prefix"},
},
wantErr: true,
},
{
name: "NAT64 prefix with wrong mask length should fail",
args: args{
source: &testutils.MockSource{},
nat64Prefixes: []string{"2001:db8::/64"},
},
wantErr: true,
},
{
name: "IPv4 address as NAT64 prefix should fail",
args: args{
source: &testutils.MockSource{},
nat64Prefixes: []string{"192.0.2.0/24"},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
src, err := NewNAT64Source(tt.args.source, tt.args.nat64Prefixes)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, src)
})
}
}
Loading