2024-10-05 21:03:26 +00:00
|
|
|
package network
|
|
|
|
|
|
|
|
import (
|
2025-01-02 13:08:24 +00:00
|
|
|
"fmt"
|
2024-10-24 17:52:08 +00:00
|
|
|
"isle/bootstrap"
|
|
|
|
"isle/daemon/daecommon"
|
|
|
|
"isle/garage"
|
2024-12-26 19:37:00 +00:00
|
|
|
"isle/garage/garagesrv"
|
2024-10-24 17:52:08 +00:00
|
|
|
"isle/jsonutil"
|
|
|
|
"isle/nebula"
|
2025-01-02 13:08:24 +00:00
|
|
|
"isle/toolkit"
|
2024-12-26 19:37:00 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2024-10-05 21:03:26 +00:00
|
|
|
"testing"
|
2025-01-02 13:08:24 +00:00
|
|
|
"time"
|
2024-10-24 17:52:08 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2024-10-05 21:03:26 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestCreate(t *testing.T) {
|
|
|
|
var (
|
2024-10-06 17:38:35 +00:00
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", nil)
|
2024-10-05 21:03:26 +00:00
|
|
|
)
|
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
gotCreationParams, err := loadCreationParams(network.stateDir)
|
2024-10-24 17:52:08 +00:00
|
|
|
assert.NoError(t, err)
|
2024-10-31 12:04:19 +00:00
|
|
|
assert.Equal(
|
|
|
|
t, gotCreationParams, network.getBootstrap(t).NetworkCreationParams,
|
|
|
|
)
|
2024-10-05 21:03:26 +00:00
|
|
|
}
|
2024-10-07 20:41:46 +00:00
|
|
|
|
|
|
|
func TestLoad(t *testing.T) {
|
2024-11-12 12:42:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
t.Run("given config", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", nil)
|
|
|
|
networkConfig = network.getConfig(t)
|
|
|
|
)
|
2024-10-07 20:41:46 +00:00
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
network.opts.Config = &networkConfig
|
|
|
|
network.restart(t)
|
2024-10-24 17:52:08 +00:00
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
assert.Equal(t, networkConfig, network.getConfig(t))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("load previous config", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", nil)
|
|
|
|
networkConfig = network.getConfig(t)
|
|
|
|
)
|
|
|
|
|
|
|
|
network.opts.Config = nil
|
|
|
|
network.restart(t)
|
|
|
|
|
|
|
|
assert.Equal(t, networkConfig, network.getConfig(t))
|
2024-10-07 20:41:46 +00:00
|
|
|
})
|
2025-01-07 14:40:50 +00:00
|
|
|
|
|
|
|
t.Run("garage lmdb db engine", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", &createNetworkOpts{
|
|
|
|
garageDefaultDBEngine: garagesrv.DBEngineLMDB,
|
|
|
|
})
|
|
|
|
metaPath = h.mkDir(t, "meta").Path
|
|
|
|
)
|
|
|
|
|
|
|
|
h.logger.Info(h.ctx, "Checking that garage is using the expected db engine")
|
|
|
|
garageConfig, err := os.ReadFile(
|
|
|
|
filepath.Join(network.runtimeDir.Path, "garage-3900.toml"),
|
|
|
|
)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Contains(t,
|
|
|
|
string(garageConfig),
|
|
|
|
`db_engine = "`+garagesrv.DBEngineLMDB+`"`,
|
|
|
|
)
|
|
|
|
assert.NoFileExists(t, filepath.Join(metaPath, "db.sqlite"))
|
|
|
|
|
|
|
|
network.opts.garageDefaultDBEngine = ""
|
|
|
|
network.restart(t)
|
|
|
|
|
|
|
|
h.logger.Info(h.ctx, "Checking that garage is still using the expected db engine")
|
|
|
|
garageConfig, err = os.ReadFile(
|
|
|
|
filepath.Join(network.runtimeDir.Path, "garage-3900.toml"),
|
|
|
|
)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Contains(t,
|
|
|
|
string(garageConfig),
|
|
|
|
`db_engine = "`+garagesrv.DBEngineLMDB+`"`,
|
|
|
|
)
|
|
|
|
assert.NoFileExists(t, filepath.Join(metaPath, "db.sqlite"))
|
|
|
|
})
|
|
|
|
|
2024-10-07 20:41:46 +00:00
|
|
|
}
|
2024-10-14 10:12:43 +00:00
|
|
|
|
|
|
|
func TestJoin(t *testing.T) {
|
2024-11-12 12:42:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2024-11-05 21:31:57 +00:00
|
|
|
t.Run("simple", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
primus = h.createNetwork(t, "primus", nil)
|
|
|
|
secondus = h.joinNetwork(t, primus, "secondus", nil)
|
|
|
|
)
|
2024-10-14 10:12:43 +00:00
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
assert.Equal(t, primus.getHostsByName(t), secondus.getHostsByName(t))
|
2024-11-05 21:31:57 +00:00
|
|
|
})
|
|
|
|
|
2025-01-08 11:00:49 +00:00
|
|
|
t.Run("with alloc", func(t *testing.T) {
|
2024-11-05 21:31:57 +00:00
|
|
|
var (
|
2025-01-08 11:00:49 +00:00
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
primus = h.createNetwork(t, "primus", nil)
|
|
|
|
secondusBlocker = toolkit.NewTestBlocker(t)
|
|
|
|
secondusRuntimeDir = h.mkDir(t, "runtime")
|
|
|
|
)
|
|
|
|
|
|
|
|
secondusBlocker.Expect("Children.Reload.postReloadNebula").Then(
|
|
|
|
t, h.ctx, func() {
|
|
|
|
h.logger.Info(h.ctx, "Checking that firewall was updated with new alloc")
|
|
|
|
assertFirewallInboundEquals(
|
|
|
|
t, secondusRuntimeDir, []daecommon.ConfigFirewallRule{
|
|
|
|
{Port: "any", Proto: "icmp", Host: "any"},
|
|
|
|
{Port: "3900", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3901", Proto: "tcp", Host: "any"},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
},
|
2024-11-05 21:31:57 +00:00
|
|
|
)
|
|
|
|
|
2025-01-08 11:00:49 +00:00
|
|
|
secondus := h.joinNetwork(t, primus, "secondus", &joinNetworkOpts{
|
|
|
|
networkConfigOpts: &networkConfigOpts{
|
|
|
|
numStorageAllocs: 1,
|
|
|
|
},
|
|
|
|
blocker: secondusBlocker,
|
|
|
|
runtimeDir: secondusRuntimeDir,
|
|
|
|
})
|
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "reloading primus' hosts")
|
2024-11-05 21:31:57 +00:00
|
|
|
assert.NoError(t, primus.Network.(*network).reloadHosts(h.ctx))
|
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
assert.Equal(t, primus.getHostsByName(t), secondus.getHostsByName(t))
|
2025-01-02 13:08:24 +00:00
|
|
|
assertGarageLayout(t, map[*integrationHarnessNetwork]int{
|
|
|
|
primus: 3,
|
|
|
|
secondus: 1,
|
|
|
|
})
|
|
|
|
})
|
2024-10-14 10:12:43 +00:00
|
|
|
}
|
2024-10-23 18:18:11 +00:00
|
|
|
|
2024-12-07 19:39:13 +00:00
|
|
|
func TestNetwork_GetBootstrap(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
currBootstrap, err := network.GetBootstrap(h.ctx)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(
|
|
|
|
t, nebula.HostPrivateCredentials{}, currBootstrap.PrivateCredentials,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-12-12 19:20:27 +00:00
|
|
|
func TestNetwork_CreateHost(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// Normal functionality of this method is tested as part of
|
|
|
|
// `integrationHarness.joinNetwork`. This tests various extra behavior.
|
|
|
|
|
|
|
|
t.Run("ErrIPInUse", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", nil)
|
|
|
|
hostName = nebula.HostName("secondus")
|
|
|
|
)
|
|
|
|
|
|
|
|
_, err := network.CreateHost(h.ctx, hostName, CreateHostOpts{
|
|
|
|
IP: network.getBootstrap(t).ThisHost().IP(),
|
|
|
|
})
|
|
|
|
assert.ErrorIs(t, err, ErrIPInUse)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-10-24 17:52:08 +00:00
|
|
|
func TestNetwork_SetConfig(t *testing.T) {
|
2024-11-12 12:42:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2024-11-08 16:46:44 +00:00
|
|
|
allocsToRoles := func(
|
2024-10-31 12:04:19 +00:00
|
|
|
hostName nebula.HostName, allocs []bootstrap.GarageHostInstance,
|
2024-11-08 16:46:44 +00:00
|
|
|
) []garage.Role {
|
|
|
|
roles := make([]garage.Role, len(allocs))
|
2024-10-31 12:04:19 +00:00
|
|
|
for i := range allocs {
|
2024-11-08 16:46:44 +00:00
|
|
|
roles[i] = garage.Role{
|
2024-10-31 12:04:19 +00:00
|
|
|
ID: allocs[i].ID,
|
|
|
|
Capacity: 1_000_000_000,
|
|
|
|
Zone: string(hostName),
|
|
|
|
Tags: []string{},
|
|
|
|
}
|
|
|
|
}
|
2024-11-08 16:46:44 +00:00
|
|
|
return roles
|
2024-10-31 12:04:19 +00:00
|
|
|
}
|
|
|
|
|
2024-12-26 19:37:00 +00:00
|
|
|
t.Run("add storage alloc/simple", func(t *testing.T) {
|
2024-10-24 17:52:08 +00:00
|
|
|
var (
|
2025-01-08 11:00:49 +00:00
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
blocker = toolkit.NewTestBlocker(t)
|
|
|
|
network = h.createNetwork(t, "primus", &createNetworkOpts{
|
|
|
|
blocker: blocker,
|
|
|
|
})
|
2024-10-31 12:04:19 +00:00
|
|
|
networkConfig = network.getConfig(t)
|
2024-12-27 10:51:53 +00:00
|
|
|
metaPath = h.mkDir(t, "meta").Path
|
2024-10-24 17:52:08 +00:00
|
|
|
)
|
|
|
|
|
2024-10-31 12:04:19 +00:00
|
|
|
networkConfig.Storage.Allocations = append(
|
|
|
|
networkConfig.Storage.Allocations,
|
2024-10-24 17:52:08 +00:00
|
|
|
daecommon.ConfigStorageAllocation{
|
|
|
|
DataPath: h.mkDir(t, "data").Path,
|
2024-12-27 10:51:53 +00:00
|
|
|
MetaPath: metaPath,
|
2024-10-24 17:52:08 +00:00
|
|
|
Capacity: 1,
|
2025-01-08 11:00:49 +00:00
|
|
|
S3APIPort: 4901,
|
|
|
|
RPCPort: 4900,
|
2024-10-24 17:52:08 +00:00
|
|
|
AdminPort: 4902,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2025-01-08 11:00:49 +00:00
|
|
|
blocker.Expect("Children.Reload.postReloadNebula").Then(
|
|
|
|
t, h.ctx, func() {
|
|
|
|
h.logger.Info(h.ctx, "Checking that firewall was updated with new alloc")
|
|
|
|
assertFirewallInboundEquals(
|
|
|
|
t, network.runtimeDir, []daecommon.ConfigFirewallRule{
|
|
|
|
{Port: "any", Proto: "icmp", Host: "any"},
|
|
|
|
{Port: "3900", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3901", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3910", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3911", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3920", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3921", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "4900", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "4901", Proto: "tcp", Host: "any"},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2024-10-31 12:04:19 +00:00
|
|
|
assert.NoError(t, network.SetConfig(h.ctx, networkConfig))
|
2024-10-24 17:52:08 +00:00
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that the Host information was updated")
|
2024-10-31 12:04:19 +00:00
|
|
|
newHostsByName := network.getHostsByName(t)
|
2024-10-24 17:52:08 +00:00
|
|
|
newHost, ok := newHostsByName[network.hostName]
|
|
|
|
assert.True(t, ok)
|
|
|
|
|
|
|
|
allocs := newHost.HostConfigured.Garage.Instances
|
|
|
|
assert.Len(t, allocs, 4)
|
|
|
|
|
|
|
|
newAlloc := allocs[3]
|
|
|
|
assert.NotEmpty(t, newAlloc.ID)
|
|
|
|
newAlloc.ID = ""
|
|
|
|
assert.Equal(t, bootstrap.GarageHostInstance{
|
2025-01-08 11:00:49 +00:00
|
|
|
S3APIPort: 4901,
|
|
|
|
RPCPort: 4900,
|
2024-10-24 17:52:08 +00:00
|
|
|
}, newAlloc)
|
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that the bootstrap file was written with the new host config")
|
2024-10-24 17:52:08 +00:00
|
|
|
var storedBootstrap bootstrap.Bootstrap
|
|
|
|
assert.NoError(t, jsonutil.LoadFile(
|
|
|
|
&storedBootstrap, bootstrap.StateDirPath(network.stateDir.Path),
|
|
|
|
))
|
|
|
|
assert.Equal(t, newHostsByName, storedBootstrap.Hosts)
|
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that garage layout contains the new allocation")
|
2024-11-08 16:46:44 +00:00
|
|
|
expRoles := allocsToRoles(network.hostName, allocs)
|
2024-10-31 12:04:19 +00:00
|
|
|
layout, err := network.garageAdminClient(t).GetLayout(h.ctx)
|
|
|
|
assert.NoError(t, err)
|
2024-11-08 16:46:44 +00:00
|
|
|
assert.ElementsMatch(t, expRoles, layout.Roles)
|
2024-12-26 19:37:00 +00:00
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that garage is using the expected db engine")
|
2024-12-26 19:37:00 +00:00
|
|
|
garageConfig, err := os.ReadFile(
|
2025-01-08 11:00:49 +00:00
|
|
|
filepath.Join(network.runtimeDir.Path, "garage-4900.toml"),
|
2024-12-26 19:37:00 +00:00
|
|
|
)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Contains(t,
|
|
|
|
string(garageConfig),
|
|
|
|
`db_engine = "`+garagesrv.DBEngineSqlite+`"`,
|
|
|
|
)
|
2024-12-27 10:51:53 +00:00
|
|
|
assert.FileExists(t, filepath.Join(metaPath, "db.sqlite"))
|
2024-12-26 19:37:00 +00:00
|
|
|
})
|
|
|
|
|
2025-01-08 11:00:49 +00:00
|
|
|
t.Run("add storage alloc/on second host", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
primus = h.createNetwork(t, "primus", nil)
|
|
|
|
secondusBlocker = toolkit.NewTestBlocker(t)
|
|
|
|
secondus = h.joinNetwork(t, primus, "secondus", &joinNetworkOpts{
|
|
|
|
blocker: secondusBlocker,
|
|
|
|
})
|
|
|
|
secondusNetworkConfig = secondus.getConfig(t)
|
|
|
|
)
|
|
|
|
|
|
|
|
secondusBlocker.Expect("Children.Reload.postReloadNebula").Then(
|
|
|
|
t, h.ctx, func() {
|
|
|
|
h.logger.Info(h.ctx, "Checking that firewall was updated with new alloc")
|
|
|
|
assertFirewallInboundEquals(
|
|
|
|
t, secondus.runtimeDir, []daecommon.ConfigFirewallRule{
|
|
|
|
{Port: "any", Proto: "icmp", Host: "any"},
|
|
|
|
{Port: "3900", Proto: "tcp", Host: "any"},
|
|
|
|
{Port: "3901", Proto: "tcp", Host: "any"},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
secondusNetworkConfig.Storage.Allocations = append(
|
|
|
|
secondusNetworkConfig.Storage.Allocations,
|
|
|
|
daecommon.ConfigStorageAllocation{
|
|
|
|
DataPath: h.mkDir(t, "data").Path,
|
|
|
|
MetaPath: h.mkDir(t, "meta").Path,
|
|
|
|
Capacity: 1,
|
|
|
|
S3APIPort: 3901,
|
|
|
|
RPCPort: 3900,
|
|
|
|
AdminPort: 3902,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
assert.NoError(t, secondus.SetConfig(h.ctx, secondusNetworkConfig))
|
|
|
|
|
|
|
|
assertGarageLayout(t, map[*integrationHarnessNetwork]int{
|
|
|
|
primus: 3,
|
|
|
|
secondus: 1,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2024-10-31 12:04:19 +00:00
|
|
|
t.Run("remove storage alloc", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", &createNetworkOpts{
|
|
|
|
numStorageAllocs: 4,
|
|
|
|
})
|
|
|
|
networkConfig = network.getConfig(t)
|
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
prevHost = network.getHostsByName(t)[network.hostName]
|
|
|
|
removedAlloc = networkConfig.Storage.Allocations[3]
|
2024-10-23 18:18:11 +00:00
|
|
|
)
|
2024-10-24 17:52:08 +00:00
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
var removedGarageInst bootstrap.GarageHostInstance
|
|
|
|
for _, removedGarageInst = range prevHost.Garage.Instances {
|
|
|
|
if removedGarageInst.RPCPort == removedAlloc.RPCPort {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-31 12:04:19 +00:00
|
|
|
networkConfig.Storage.Allocations = networkConfig.Storage.Allocations[:3]
|
|
|
|
assert.NoError(t, network.SetConfig(h.ctx, networkConfig))
|
2024-10-24 17:52:08 +00:00
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that the Host information was updated")
|
2024-10-31 12:04:19 +00:00
|
|
|
newHostsByName := network.getHostsByName(t)
|
|
|
|
newHost, ok := newHostsByName[network.hostName]
|
|
|
|
assert.True(t, ok)
|
2024-10-24 17:52:08 +00:00
|
|
|
|
2024-10-31 12:04:19 +00:00
|
|
|
allocs := newHost.HostConfigured.Garage.Instances
|
|
|
|
assert.Len(t, allocs, 3)
|
|
|
|
assert.NotContains(t, allocs, removedGarageInst)
|
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that the bootstrap file was written with the new host config")
|
2024-10-31 12:04:19 +00:00
|
|
|
var storedBootstrap bootstrap.Bootstrap
|
|
|
|
assert.NoError(t, jsonutil.LoadFile(
|
|
|
|
&storedBootstrap, bootstrap.StateDirPath(network.stateDir.Path),
|
|
|
|
))
|
|
|
|
assert.Equal(t, newHostsByName, storedBootstrap.Hosts)
|
|
|
|
|
2025-01-07 14:40:50 +00:00
|
|
|
h.logger.Info(h.ctx, "Checking that garage layout contains the new allocation")
|
2024-11-08 16:46:44 +00:00
|
|
|
expRoles := allocsToRoles(network.hostName, allocs)
|
2024-10-31 12:04:19 +00:00
|
|
|
layout, err := network.garageAdminClient(t).GetLayout(h.ctx)
|
|
|
|
assert.NoError(t, err)
|
2024-11-08 16:46:44 +00:00
|
|
|
assert.ElementsMatch(t, expRoles, layout.Roles)
|
2024-10-24 17:52:08 +00:00
|
|
|
})
|
2024-10-31 12:04:19 +00:00
|
|
|
|
2024-11-11 14:32:15 +00:00
|
|
|
t.Run("changes reflected after restart", func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
network = h.createNetwork(t, "primus", &createNetworkOpts{
|
|
|
|
numStorageAllocs: 4,
|
|
|
|
})
|
|
|
|
networkConfig = network.getConfig(t)
|
|
|
|
)
|
|
|
|
|
|
|
|
networkConfig.Storage.Allocations = networkConfig.Storage.Allocations[:3]
|
|
|
|
assert.NoError(t, network.SetConfig(h.ctx, networkConfig))
|
|
|
|
|
|
|
|
network.opts.Config = nil
|
|
|
|
network.restart(t)
|
|
|
|
|
|
|
|
assert.Equal(t, networkConfig, network.getConfig(t))
|
|
|
|
})
|
2024-10-23 18:18:11 +00:00
|
|
|
}
|
2025-01-07 14:40:50 +00:00
|
|
|
|
|
|
|
func TestNetwork_glmStateTransition(t *testing.T) {
|
|
|
|
var (
|
|
|
|
h = newIntegrationHarness(t)
|
|
|
|
primus = h.createNetwork(t, "primus", nil)
|
|
|
|
secondus = h.joinNetwork(t, primus, "secondus", &joinNetworkOpts{
|
|
|
|
networkConfigOpts: &networkConfigOpts{
|
|
|
|
numStorageAllocs: 1,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
secondusNetworkConfig = secondus.getConfig(t)
|
|
|
|
secondusAdminClient = secondus.garageAdminClient(t)
|
|
|
|
secondusNetworkDirect = secondus.Network.(*network)
|
|
|
|
secondsBootstrapHost = primus.getHostsByName(t)["secondus"]
|
|
|
|
)
|
|
|
|
|
|
|
|
assertGarageLayout(t, map[*integrationHarnessNetwork]int{
|
|
|
|
primus: 3,
|
|
|
|
secondus: 1,
|
|
|
|
})
|
|
|
|
|
|
|
|
secondusNetworkConfig.Storage.Allocations = nil
|
|
|
|
assert.NoError(t, secondus.SetConfig(h.ctx, secondusNetworkConfig))
|
|
|
|
|
|
|
|
assert.Len(t, secondusNetworkDirect.children.ActiveStorageAllocations(), 1)
|
|
|
|
|
|
|
|
h.logger.Info(h.ctx, "Waiting for secondus to finish draining")
|
|
|
|
err := toolkit.UntilTrue(
|
|
|
|
h.ctx, h.logger, 1*time.Second, func() (bool, error) {
|
|
|
|
status, err := secondusAdminClient.Status(h.ctx)
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("getting status: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, node := range status.Nodes {
|
|
|
|
if node.Addr.Addr() == secondsBootstrapHost.IP() {
|
|
|
|
return !node.Draining, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, fmt.Errorf("secondus not found in cluster status: %+v", status)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
h.logger.Info(h.ctx, "Running GLM state transition")
|
|
|
|
assert.NoError(t, secondusNetworkDirect.glmStateTransition(h.ctx))
|
|
|
|
|
|
|
|
assertGarageLayout(t, map[*integrationHarnessNetwork]int{
|
|
|
|
primus: 3,
|
|
|
|
})
|
|
|
|
assert.Empty(t, secondusNetworkDirect.children.ActiveStorageAllocations())
|
|
|
|
}
|