mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-01 20:41:28 +02:00
149 lines
5.7 KiB
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)
|
|
}
|