mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-21 11:46:37 +00:00
62e7f983ee
* test: assert the gateway->vpcd->OVN crossing in the integration tier
The tier already ran the real VPCServiceImpl for the AWS-facing half, but
nothing consumed the vpc.* events it published: the SG topics were answered
by a canned {"success":true} and the fire-and-forget topology topics were
dropped. Both sides of that wire were tested only against stubs, so the join
was asserted nowhere below the live e2e tier.
Wire a real subscribers.Subscriber over a real in-process OVN Northbound DB
(ovntest.StartNB), opt-in per test so only tests that assert OVN state pay
the startup cost. StartDaemonLite gains WithRealVPCD to suppress its stubs,
since a stub and the subscriber both answering one request-reply would race.
Scope is the crossing, not NB row shapes — those stay with the reconcile
scenario tests. Everything host-dependent (ovn-controller, OVS, taps, netns,
nftables, packet paths) remains the live tier's claim.
* fix: make the integration tier re-runnable and quiet the ensure probe
Two defects the vpcd/OVN work surfaced.
The tier was green at -count=1 and red package-wide at -count=2. Test
accounts were keyed by t.Name(), which is unique among tests but repeats
across passes in one TestMain, so a second pass inherited the first pass's
JetStream namespace — including an ECR signing key sealed with a master key
StartGateway regenerates per call. Key each account off a counter instead.
TestRunInstances_ClientTokenIdempotency then collided with itself for the
same reason: its dedup store outlives a pass, so its fixed ClientToken made
the second pass's opening launch look like a replay. Suffix the tokens per
invocation.
ensureNamedRowOps' wait-op is built to fail fast when the row it guards
already exists, which is the ordinary idempotent path, but transactOps
reported it as "OVSDB operation failed" at ERROR. Every re-ensure emitted
one, drowning real faults in the log sink. Classify that one result as the
probe outcome it is and log it at Debug.
* test: cover transactOps' failed-result paths
The classifier split one log line into two branches and neither was
exercised: transactOps sat at 31% because EnsureLogicalRouter's cache
lookup absorbs a re-ensure before it ever transacts, so no unit test
reached a failed operation result.
Drive both kinds directly against a real NB — the guard probe finding an
existing row, and two same-named inserts violating the schema's name
index — since only the second is a fault and they now log at different
levels. transactOps goes to 94%; the remainder is the transport-error
return, which needs a broken connection to reach.
100 lines
3.5 KiB
Go
100 lines
3.5 KiB
Go
// Package vpcd builds the network managers a live vpcd runs, wired against a
|
|
// real in-process OVN Northbound DB (network/ovn/ovntest). It exists so tests
|
|
// outside the network/ tree can assert against genuine NB rows instead of the
|
|
// hand-rolled ovn/mock.
|
|
//
|
|
// network/reconcile's scenario tests construct the same set of managers, but
|
|
// they do it inside a _test.go and so cannot be imported. This package
|
|
// deliberately repeats that wiring rather than exporting a helper out of
|
|
// network/: dependencies run tests/ -> spinifex/, and inverting that to save a
|
|
// block of construction is the worse trade.
|
|
package vpcd
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/mulgadc/spinifex/spinifex/network/external"
|
|
"github.com/mulgadc/spinifex/spinifex/network/ovn"
|
|
"github.com/mulgadc/spinifex/spinifex/network/ovn/ovntest"
|
|
"github.com/mulgadc/spinifex/spinifex/network/policy"
|
|
"github.com/mulgadc/spinifex/spinifex/network/subscribers"
|
|
"github.com/mulgadc/spinifex/spinifex/network/topology"
|
|
)
|
|
|
|
// connectTimeout bounds the initial OVSDB handshake. The server is in-process
|
|
// on a unix socket, so this only ever fires on a genuine failure.
|
|
const connectTimeout = 5 * time.Second
|
|
|
|
// Fixture is a connected OVN NB DB plus the managers that drive it. OVN is
|
|
// exposed so tests can read rows back; Subscribers is the config a
|
|
// subscribers.Subscriber is built from.
|
|
type Fixture struct {
|
|
// OVN is the connected client, for asserting NB state directly.
|
|
OVN ovn.Client
|
|
// Subscribers carries every manager subscribers.New requires. MAC is left
|
|
// nil: flushing SB MAC_Binding rows needs a real SB DB, which this fixture
|
|
// does not run, and a nil flusher makes the flush a no-op.
|
|
Subscribers subscribers.Config
|
|
}
|
|
|
|
// Start boots an in-process OVN NB server and returns the managers wired to
|
|
// it. The server and client are torn down via t.Cleanup.
|
|
//
|
|
// The managers are the production types a live vpcd constructs
|
|
// (spinifex/vpcd/vpcd.go), minus the host-dependent options: NAT runs in
|
|
// distributed mode with no chassis list, IGW allocates link-local addresses
|
|
// rather than drawing from a configured pool, and nothing seeds a nexthop MAC
|
|
// or waits on an OpenFlow barrier. Those all reach for the host datapath,
|
|
// which belongs to the live e2e tier.
|
|
func Start(t testing.TB) *Fixture {
|
|
t.Helper()
|
|
|
|
nb := ovntest.StartNB(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), connectTimeout)
|
|
defer cancel()
|
|
cli := ovn.NewLiveClient(nb.Endpoint)
|
|
if err := cli.Connect(ctx); err != nil {
|
|
t.Fatalf("vpcd fixture: LiveClient.Connect: %v", err)
|
|
}
|
|
t.Cleanup(cli.Close)
|
|
|
|
sg := policy.NewSecurityGroupManager(cli)
|
|
nat, err := policy.NewNATManager(cli, policy.NATModeDistributed)
|
|
if err != nil {
|
|
t.Fatalf("vpcd fixture: NewNATManager: %v", err)
|
|
}
|
|
routes := policy.NewRouteManager(cli)
|
|
igw, err := external.NewIGWManager(external.IGWManagerConfig{
|
|
OVN: cli,
|
|
Routes: routes,
|
|
NAT: nat,
|
|
Allocator: external.LinkLocalAllocator{},
|
|
NATMode: policy.NATModeDistributed,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("vpcd fixture: NewIGWManager: %v", err)
|
|
}
|
|
eip, err := external.NewEIPManager(nat, nil)
|
|
if err != nil {
|
|
t.Fatalf("vpcd fixture: NewEIPManager: %v", err)
|
|
}
|
|
natgw, err := external.NewNATGWManager(nat)
|
|
if err != nil {
|
|
t.Fatalf("vpcd fixture: NewNATGWManager: %v", err)
|
|
}
|
|
|
|
return &Fixture{
|
|
OVN: cli,
|
|
Subscribers: subscribers.Config{
|
|
Topology: topology.NewLiveManager(cli),
|
|
SG: sg,
|
|
EIP: eip,
|
|
NATGW: natgw,
|
|
IGW: igw,
|
|
},
|
|
}
|
|
}
|