Files
netbird/shared/management/networkmap/privatezones_test.go

149 lines
5.7 KiB
Go

package networkmap
import (
"net/netip"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
)
func proxyPeer(id, ip, cluster string, connected bool) *nmdata.Peer {
return &nmdata.Peer{
ID: id, Key: id + "-key", IP: netip.MustParseAddr(ip), Connected: connected,
ProxyMeta: nmdata.ProxyMeta{Embedded: true, Cluster: cluster},
}
}
func privateService(id, domain, cluster string, groups ...string) *nmdata.Service {
return &nmdata.Service{
ID: id, Enabled: true, Private: true, Mode: "http",
Domain: domain, ProxyCluster: cluster, AccessGroups: groups,
}
}
func twinWithProxy(services ...*nmdata.Service) *NetworkMapData {
return &NetworkMapData{
Peers: map[string]*nmdata.Peer{
"proxy-1": proxyPeer("proxy-1", "100.64.0.99", "eu.proxy.netbird.io", true),
},
Services: services,
}
}
// An agent-network service is synthesised in memory and never persisted, so it
// only ever reaches the twin through nmd.Services. Deriving the zone from that
// same field is what stops it from arriving with an ACL and no name.
func TestBuildPrivateServiceCandidates_SynthesisedServiceGetsAZone(t *testing.T) {
nmd := twinWithProxy(privateService(
"agent-network-acct-1", "acct-1.agent.netbird.io", "eu.proxy.netbird.io", "grp-admins"))
nmd.BuildPrivateServiceCandidates()
require.Len(t, nmd.PrivateServiceCandidates, 0,
"a service whose domain sits under no registered apex publishes nothing")
nmd.Domains = []nmdata.ProxyDomain{
{Domain: "agent.netbird.io", TargetCluster: "eu.proxy.netbird.io"},
}
nmd.BuildPrivateServiceCandidates()
require.Len(t, nmd.PrivateServiceCandidates, 1)
got := nmd.PrivateServiceCandidates[0]
assert.Equal(t, []string{"grp-admins"}, got.AccessGroups)
assert.Equal(t, "agent.netbird.io.", got.Zone.Domain, "apex is the registered domain, not the service FQDN")
assert.True(t, got.Zone.NonAuthoritative, "zone stays match-only")
assert.True(t, got.Zone.SearchDomainDisabled)
require.Len(t, got.Zone.Records, 1)
assert.Equal(t, nmdata.SimpleRecord{
Name: "acct-1.agent.netbird.io.", Type: 1, Class: "IN", TTL: 5, RData: "100.64.0.99",
}, got.Zone.Records[0])
}
func TestBuildPrivateServiceCandidates_ClusterApexNeedsNoRegisteredDomain(t *testing.T) {
nmd := twinWithProxy(privateService("svc-1", "myapp.eu.proxy.netbird.io", "eu.proxy.netbird.io", "grp-admins"))
nmd.BuildPrivateServiceCandidates()
require.Len(t, nmd.PrivateServiceCandidates, 1)
assert.Equal(t, "eu.proxy.netbird.io.", nmd.PrivateServiceCandidates[0].Zone.Domain)
}
func TestBuildPrivateServiceCandidates_LongestRegisteredApexWins(t *testing.T) {
nmd := twinWithProxy(privateService("svc-1", "app.sub.example.com", "eu.proxy.netbird.io", "grp-admins"))
nmd.Domains = []nmdata.ProxyDomain{
{Domain: "example.com", TargetCluster: "eu.proxy.netbird.io"},
{Domain: "sub.example.com", TargetCluster: "eu.proxy.netbird.io"},
{Domain: "other.com", TargetCluster: "eu.proxy.netbird.io"},
}
nmd.BuildPrivateServiceCandidates()
require.Len(t, nmd.PrivateServiceCandidates, 1)
assert.Equal(t, "sub.example.com.", nmd.PrivateServiceCandidates[0].Zone.Domain)
}
func TestBuildPrivateServiceCandidates_RegisteredApexOfAnotherClusterIsIgnored(t *testing.T) {
nmd := twinWithProxy(privateService("svc-1", "app.example.com", "eu.proxy.netbird.io", "grp-admins"))
nmd.Domains = []nmdata.ProxyDomain{
{Domain: "example.com", TargetCluster: "us.proxy.netbird.io"},
}
nmd.BuildPrivateServiceCandidates()
assert.Empty(t, nmd.PrivateServiceCandidates)
}
// A disconnected proxy peer's tunnel IP does not answer, so publishing it
// black-holes the name for as long as a client caches the record.
func TestBuildPrivateServiceCandidates_OnlyConnectedProxyPeersSurface(t *testing.T) {
nmd := twinWithProxy(privateService("svc-1", "myapp.eu.proxy.netbird.io", "eu.proxy.netbird.io", "grp-admins"))
nmd.Peers["proxy-2"] = proxyPeer("proxy-2", "100.64.0.100", "eu.proxy.netbird.io", false)
nmd.BuildPrivateServiceCandidates()
require.Len(t, nmd.PrivateServiceCandidates, 1)
require.Len(t, nmd.PrivateServiceCandidates[0].Zone.Records, 1)
assert.Equal(t, "100.64.0.99", nmd.PrivateServiceCandidates[0].Zone.Records[0].RData)
nmd.Peers["proxy-1"].Connected = false
nmd.BuildPrivateServiceCandidates()
assert.Empty(t, nmd.PrivateServiceCandidates, "no connected proxy peer means no zone at all")
}
func TestBuildPrivateServiceCandidates_SkipsServicesThatGrantNothing(t *testing.T) {
cases := map[string]func(*nmdata.Service){
"disabled": func(s *nmdata.Service) { s.Enabled = false },
"not private": func(s *nmdata.Service) { s.Private = false },
"no access groups": func(s *nmdata.Service) { s.AccessGroups = nil },
"no domain": func(s *nmdata.Service) { s.Domain = "" },
"other cluster": func(s *nmdata.Service) { s.ProxyCluster = "us.proxy.netbird.io" },
}
for name, mutate := range cases {
t.Run(name, func(t *testing.T) {
svc := privateService("svc-1", "myapp.eu.proxy.netbird.io", "eu.proxy.netbird.io", "grp-admins")
mutate(svc)
nmd := twinWithProxy(svc)
nmd.BuildPrivateServiceCandidates()
assert.Empty(t, nmd.PrivateServiceCandidates)
})
}
}
func TestBuildPrivateServiceCandidates_MultipleConnectedProxyPeersEachGetARecord(t *testing.T) {
nmd := twinWithProxy(privateService("svc-1", "myapp.eu.proxy.netbird.io", "eu.proxy.netbird.io", "grp-admins"))
nmd.Peers["proxy-2"] = proxyPeer("proxy-2", "100.64.0.100", "eu.proxy.netbird.io", true)
nmd.BuildPrivateServiceCandidates()
require.Len(t, nmd.PrivateServiceCandidates, 1)
records := nmd.PrivateServiceCandidates[0].Zone.Records
require.Len(t, records, 2)
assert.Equal(t, "100.64.0.99", records[0].RData, "records are ordered by proxy peer id")
assert.Equal(t, "100.64.0.100", records[1].RData)
}