2024-11-11 14:32:15 +00:00
|
|
|
package daemon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"isle/bootstrap"
|
|
|
|
"isle/daemon/daecommon"
|
|
|
|
"isle/daemon/network"
|
2024-12-17 10:33:19 +00:00
|
|
|
"isle/nebula"
|
2024-11-11 14:32:15 +00:00
|
|
|
"isle/toolkit"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
type expectNetworkLoad struct {
|
|
|
|
creationParams bootstrap.CreationParams
|
|
|
|
networkConfig *daecommon.NetworkConfig
|
|
|
|
network *network.MockNetwork
|
|
|
|
}
|
|
|
|
|
|
|
|
type harnessOpts struct {
|
|
|
|
config daecommon.Config
|
|
|
|
expectNetworksLoaded []expectNetworkLoad
|
2024-12-14 14:57:07 +00:00
|
|
|
expectStoredConfigs map[string]daecommon.NetworkConfig
|
2024-11-11 14:32:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *harnessOpts) withDefaults() *harnessOpts {
|
|
|
|
if o == nil {
|
|
|
|
o = new(harnessOpts)
|
|
|
|
}
|
|
|
|
return o
|
|
|
|
}
|
|
|
|
|
|
|
|
type harness struct {
|
|
|
|
ctx context.Context
|
|
|
|
networkLoader *network.MockLoader
|
|
|
|
daemon *Daemon
|
|
|
|
}
|
|
|
|
|
|
|
|
func newHarness(t *testing.T, opts *harnessOpts) *harness {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
opts = opts.withDefaults()
|
|
|
|
|
|
|
|
var (
|
|
|
|
ctx = context.Background()
|
|
|
|
logger = toolkit.NewTestLogger(t)
|
|
|
|
networkLoader = network.NewMockLoader(t)
|
|
|
|
)
|
|
|
|
|
|
|
|
expectLoadable := make(
|
|
|
|
[]bootstrap.CreationParams, len(opts.expectNetworksLoaded),
|
|
|
|
)
|
|
|
|
for i, expectNetworkLoaded := range opts.expectNetworksLoaded {
|
|
|
|
expectLoadable[i] = expectNetworkLoaded.creationParams
|
2024-12-14 14:57:07 +00:00
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
networkLoader.
|
|
|
|
On(
|
|
|
|
"Load",
|
|
|
|
toolkit.MockArg[context.Context](),
|
|
|
|
toolkit.MockArg[*mlog.Logger](),
|
|
|
|
expectNetworkLoaded.creationParams,
|
|
|
|
&network.Opts{
|
|
|
|
Config: expectNetworkLoaded.networkConfig,
|
|
|
|
},
|
|
|
|
).
|
|
|
|
Return(expectNetworkLoaded.network, nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
expectNetworkLoaded.network.On("Shutdown").Return(nil).Once()
|
|
|
|
}
|
|
|
|
|
2024-12-14 14:57:07 +00:00
|
|
|
for id, networkConfig := range opts.expectStoredConfigs {
|
|
|
|
networkLoader.
|
|
|
|
On("StoredConfig", toolkit.MockArg[context.Context](), id).
|
|
|
|
Return(networkConfig, nil).
|
|
|
|
Once()
|
|
|
|
}
|
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
networkLoader.
|
|
|
|
On("Loadable", toolkit.MockArg[context.Context]()).
|
2024-12-14 14:57:07 +00:00
|
|
|
Return(expectLoadable, nil)
|
2024-11-11 14:32:15 +00:00
|
|
|
|
|
|
|
daemon, err := New(ctx, logger, networkLoader, opts.config)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
t.Log("Shutting down Daemon")
|
|
|
|
assert.NoError(t, daemon.Shutdown())
|
|
|
|
})
|
|
|
|
|
|
|
|
return &harness{ctx, networkLoader, daemon}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNew(t *testing.T) {
|
|
|
|
t.Run("no networks loaded", func(t *testing.T) {
|
|
|
|
_ = newHarness(t, nil)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("DEPRECATED network config matching", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
networkConfig = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.DNS.Resolvers = []string{"foo"}
|
|
|
|
})
|
|
|
|
config = daecommon.Config{
|
|
|
|
Networks: map[string]daecommon.NetworkConfig{
|
|
|
|
daecommon.DeprecatedNetworkID: networkConfig,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
_ = newHarness(t, &harnessOpts{
|
|
|
|
config: config,
|
|
|
|
expectNetworksLoaded: []expectNetworkLoad{
|
|
|
|
{
|
|
|
|
creationParams,
|
|
|
|
&networkConfig,
|
|
|
|
network.NewMockNetwork(t),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("network config matching", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
creationParamsA = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
creationParamsB = bootstrap.NewCreationParams("BBB", "b.com")
|
|
|
|
creationParamsC = bootstrap.NewCreationParams("CCC", "c.com")
|
|
|
|
creationParamsD = bootstrap.NewCreationParams("DDD", "d.com")
|
|
|
|
|
|
|
|
networkConfigA = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.DNS.Resolvers = []string{"foo"}
|
|
|
|
})
|
|
|
|
|
|
|
|
networkConfigB = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
2024-11-19 11:50:58 +00:00
|
|
|
c.VPN.PublicAddr = "1.2.3.4:5"
|
2024-11-11 14:32:15 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
networkConfigC = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.Storage.Allocations = []daecommon.ConfigStorageAllocation{
|
|
|
|
{
|
|
|
|
DataPath: "/path/data",
|
|
|
|
MetaPath: "/path/meta",
|
|
|
|
Capacity: 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
config = daecommon.Config{
|
|
|
|
Networks: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParamsA.ID: networkConfigA,
|
|
|
|
creationParamsB.Name: networkConfigB,
|
|
|
|
creationParamsC.Domain: networkConfigC,
|
|
|
|
"unknown": {},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
_ = newHarness(t, &harnessOpts{
|
|
|
|
config: config,
|
|
|
|
expectNetworksLoaded: []expectNetworkLoad{
|
|
|
|
{
|
|
|
|
creationParamsA,
|
|
|
|
&networkConfigA,
|
|
|
|
network.NewMockNetwork(t),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
creationParamsB,
|
|
|
|
&networkConfigB,
|
|
|
|
network.NewMockNetwork(t),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
creationParamsC,
|
|
|
|
&networkConfigC,
|
|
|
|
network.NewMockNetwork(t),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
creationParamsD,
|
|
|
|
nil,
|
|
|
|
network.NewMockNetwork(t),
|
|
|
|
},
|
|
|
|
},
|
2024-12-14 14:57:07 +00:00
|
|
|
expectStoredConfigs: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParamsD.ID: daecommon.NewNetworkConfig(nil),
|
|
|
|
},
|
2024-11-11 14:32:15 +00:00
|
|
|
})
|
|
|
|
})
|
2024-12-14 14:57:07 +00:00
|
|
|
|
|
|
|
t.Run("invalid config", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
ctx = context.Background()
|
|
|
|
logger = toolkit.NewTestLogger(t)
|
|
|
|
networkLoader = network.NewMockLoader(t)
|
|
|
|
|
|
|
|
creationParamsA = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
creationParamsB = bootstrap.NewCreationParams("BBB", "b.com")
|
|
|
|
|
|
|
|
networkConfigA = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.VPN.PublicAddr = "1.1.1.1:5"
|
|
|
|
})
|
|
|
|
|
|
|
|
networkConfigB = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.VPN.PublicAddr = "2.2.2.2:5"
|
|
|
|
})
|
|
|
|
|
|
|
|
config = daecommon.Config{
|
|
|
|
Networks: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParamsA.ID: networkConfigA,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
networkLoader.
|
|
|
|
On("Loadable", toolkit.MockArg[context.Context]()).
|
|
|
|
Return(
|
|
|
|
[]bootstrap.CreationParams{creationParamsA, creationParamsB},
|
|
|
|
nil,
|
|
|
|
).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
networkLoader.
|
|
|
|
On(
|
|
|
|
"StoredConfig",
|
|
|
|
toolkit.MockArg[context.Context](),
|
|
|
|
creationParamsB.ID,
|
|
|
|
).
|
|
|
|
Return(networkConfigB, nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
_, err := New(ctx, logger, networkLoader, config)
|
|
|
|
assert.ErrorContains(t, err, "two networks with the same vpn.public_addr port")
|
|
|
|
})
|
2024-11-11 14:32:15 +00:00
|
|
|
}
|
|
|
|
|
2024-12-17 10:33:19 +00:00
|
|
|
func TestDaemon_CreateNetwork(t *testing.T) {
|
|
|
|
t.Run("ErrManagedNetworkConfig", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
networkConfig = daecommon.NewNetworkConfig(nil)
|
|
|
|
h = newHarness(t, &harnessOpts{
|
|
|
|
config: daecommon.Config{
|
|
|
|
Networks: map[string]daecommon.NetworkConfig{
|
|
|
|
"AAA": networkConfig,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
ipNet = nebula.MustParseIPNet(t, "172.16.0.0/24")
|
|
|
|
)
|
|
|
|
|
|
|
|
err := h.daemon.CreateNetwork(
|
|
|
|
h.ctx,
|
|
|
|
creationParams,
|
|
|
|
ipNet,
|
|
|
|
nebula.HostName("foo"),
|
|
|
|
&CreateNetworkOpts{Config: &networkConfig},
|
|
|
|
)
|
|
|
|
assert.ErrorIs(t, err, ErrManagedNetworkConfig)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("ErrAlreadyJoined", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
networkConfig = daecommon.NewNetworkConfig(nil)
|
|
|
|
h = newHarness(t, &harnessOpts{
|
|
|
|
expectNetworksLoaded: []expectNetworkLoad{{
|
|
|
|
creationParams, nil, network.NewMockNetwork(t),
|
|
|
|
}},
|
|
|
|
expectStoredConfigs: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParams.ID: networkConfig,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
ipNet = nebula.MustParseIPNet(t, "172.16.0.0/24")
|
|
|
|
)
|
|
|
|
|
|
|
|
err := h.daemon.CreateNetwork(
|
|
|
|
h.ctx,
|
|
|
|
bootstrap.NewCreationParams("AAA", "aaa.com"),
|
|
|
|
ipNet,
|
|
|
|
nebula.HostName("foo"),
|
|
|
|
nil,
|
|
|
|
)
|
|
|
|
assert.ErrorIs(t, err, ErrAlreadyJoined)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("success/config given", func(t *testing.T) {
|
|
|
|
networkA := network.NewMockNetwork(t)
|
|
|
|
networkA.On("Shutdown").Return(nil).Once()
|
|
|
|
|
|
|
|
var (
|
|
|
|
h = newHarness(t, nil)
|
|
|
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
networkConfig = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.VPN.PublicAddr = "1.2.3.4:50"
|
|
|
|
})
|
|
|
|
ipNet = nebula.MustParseIPNet(t, "172.16.0.0/24")
|
|
|
|
hostName = nebula.HostName("foo")
|
|
|
|
)
|
|
|
|
|
|
|
|
h.networkLoader.
|
|
|
|
On(
|
|
|
|
"Create",
|
|
|
|
toolkit.MockArg[context.Context](),
|
|
|
|
toolkit.MockArg[*mlog.Logger](),
|
|
|
|
creationParams,
|
|
|
|
ipNet,
|
|
|
|
hostName,
|
|
|
|
&network.Opts{
|
|
|
|
Config: &networkConfig,
|
|
|
|
},
|
|
|
|
).
|
|
|
|
Return(networkA, nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
err := h.daemon.CreateNetwork(
|
|
|
|
h.ctx,
|
|
|
|
creationParams,
|
|
|
|
ipNet,
|
|
|
|
hostName,
|
|
|
|
&CreateNetworkOpts{
|
|
|
|
Config: &networkConfig,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Contains(t, h.daemon.networks, creationParams.ID)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("success/no config given", func(t *testing.T) {
|
|
|
|
networkA := network.NewMockNetwork(t)
|
|
|
|
networkA.On("Shutdown").Return(nil).Once()
|
|
|
|
|
|
|
|
var (
|
|
|
|
h = newHarness(t, nil)
|
|
|
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
ipNet = nebula.MustParseIPNet(t, "172.16.0.0/24")
|
|
|
|
hostName = nebula.HostName("foo")
|
|
|
|
)
|
|
|
|
|
|
|
|
h.networkLoader.
|
|
|
|
On(
|
|
|
|
"Create",
|
|
|
|
toolkit.MockArg[context.Context](),
|
|
|
|
toolkit.MockArg[*mlog.Logger](),
|
|
|
|
creationParams,
|
|
|
|
ipNet,
|
|
|
|
hostName,
|
|
|
|
&network.Opts{},
|
|
|
|
).
|
|
|
|
Return(networkA, nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
err := h.daemon.CreateNetwork(
|
|
|
|
h.ctx,
|
|
|
|
creationParams,
|
|
|
|
ipNet,
|
|
|
|
hostName,
|
|
|
|
nil,
|
|
|
|
)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Contains(t, h.daemon.networks, creationParams.ID)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-12-17 15:47:33 +00:00
|
|
|
func TestDaemon_LeaveNetwork(t *testing.T) {
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
networkA = network.NewMockNetwork(t)
|
|
|
|
creationParamsA = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
h = newHarness(t, &harnessOpts{
|
|
|
|
expectNetworksLoaded: []expectNetworkLoad{{
|
|
|
|
creationParamsA, nil, networkA,
|
|
|
|
}},
|
|
|
|
expectStoredConfigs: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParamsA.ID: daecommon.NewNetworkConfig(nil),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
h.networkLoader.
|
|
|
|
On("Leave", toolkit.MockArg[context.Context](), creationParamsA).
|
|
|
|
Return(nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
ctx := WithNetwork(h.ctx, "AAA")
|
|
|
|
assert.NoError(t, h.daemon.LeaveNetwork(ctx))
|
|
|
|
|
|
|
|
joinedCreationParams, err := h.daemon.GetNetworks(h.ctx)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Empty(t, joinedCreationParams)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
func TestDaemon_SetConfig(t *testing.T) {
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
|
|
var (
|
2024-12-14 14:57:07 +00:00
|
|
|
networkA = network.NewMockNetwork(t)
|
|
|
|
creationParamsA = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
h = newHarness(t, &harnessOpts{
|
2024-11-11 14:32:15 +00:00
|
|
|
expectNetworksLoaded: []expectNetworkLoad{{
|
2024-12-14 14:57:07 +00:00
|
|
|
creationParamsA, nil, networkA,
|
2024-11-11 14:32:15 +00:00
|
|
|
}},
|
2024-12-14 14:57:07 +00:00
|
|
|
expectStoredConfigs: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParamsA.ID: daecommon.NewNetworkConfig(nil),
|
|
|
|
},
|
2024-11-11 14:32:15 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
networkConfig = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
2024-11-19 11:50:58 +00:00
|
|
|
c.VPN.PublicAddr = "1.2.3.4:5"
|
2024-11-11 14:32:15 +00:00
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
networkA.
|
|
|
|
On("SetConfig", toolkit.MockArg[context.Context](), networkConfig).
|
|
|
|
Return(nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
err := h.daemon.SetConfig(h.ctx, networkConfig)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
})
|
|
|
|
|
2024-11-18 21:25:49 +00:00
|
|
|
t.Run("ErrManagedNetworkConfig", func(t *testing.T) {
|
2024-11-11 14:32:15 +00:00
|
|
|
var (
|
|
|
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
networkA = network.NewMockNetwork(t)
|
|
|
|
networkConfig = daecommon.NewNetworkConfig(nil)
|
|
|
|
|
|
|
|
h = newHarness(t, &harnessOpts{
|
|
|
|
config: daecommon.Config{
|
|
|
|
Networks: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParams.Name: networkConfig,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectNetworksLoaded: []expectNetworkLoad{
|
|
|
|
{creationParams, &networkConfig, networkA},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
2024-11-19 11:50:58 +00:00
|
|
|
networkConfig.VPN.PublicAddr = "1.2.3.4:5"
|
2024-11-11 14:32:15 +00:00
|
|
|
err := h.daemon.SetConfig(h.ctx, networkConfig)
|
2024-11-18 21:25:49 +00:00
|
|
|
assert.ErrorIs(t, err, ErrManagedNetworkConfig)
|
2024-11-11 14:32:15 +00:00
|
|
|
})
|
2024-12-14 14:57:07 +00:00
|
|
|
|
|
|
|
t.Run("ErrInvalidConfig", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
creationParamsA = bootstrap.NewCreationParams("AAA", "a.com")
|
|
|
|
networkA = network.NewMockNetwork(t)
|
|
|
|
networkConfigA = daecommon.NewNetworkConfig(func(c *daecommon.NetworkConfig) {
|
|
|
|
c.VPN.PublicAddr = "1.2.3.4:5"
|
|
|
|
})
|
|
|
|
|
|
|
|
creationParamsB = bootstrap.NewCreationParams("BBB", "b.com")
|
|
|
|
networkB = network.NewMockNetwork(t)
|
|
|
|
networkConfigB = daecommon.NewNetworkConfig(nil)
|
|
|
|
|
|
|
|
h = newHarness(t, &harnessOpts{
|
|
|
|
expectNetworksLoaded: []expectNetworkLoad{
|
|
|
|
{creationParamsA, nil, networkA},
|
|
|
|
{creationParamsB, nil, networkB},
|
|
|
|
},
|
|
|
|
expectStoredConfigs: map[string]daecommon.NetworkConfig{
|
|
|
|
creationParamsA.ID: networkConfigA,
|
|
|
|
creationParamsB.ID: networkConfigB,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
networkA.
|
|
|
|
On("GetConfig", toolkit.MockArg[context.Context]()).
|
|
|
|
Return(networkConfigA, nil).
|
|
|
|
Once()
|
|
|
|
|
|
|
|
networkConfigB.VPN.PublicAddr = "1.1.1.1:5"
|
|
|
|
err := h.daemon.SetConfig(WithNetwork(h.ctx, "BBB"), networkConfigB)
|
|
|
|
assert.ErrorIs(t, err, network.ErrInvalidConfig)
|
|
|
|
})
|
2024-11-11 14:32:15 +00:00
|
|
|
}
|