daemon split (1/5): extract *HostNetwork service
First phase of splitting the daemon god-struct into focused services with explicit ownership. HostNetwork now owns everything host-networking: the TAP interface pool (initializeTapPool / ensureTapPool / acquireTap / releaseTap / createTap), bridge + socket dir setup, firecracker process primitives (find/resolve/kill/wait/ensureSocketAccess/sendCtrlAltDel), DM snapshot lifecycle, NAT rule enforcement, guest DNS server lifecycle + routing setup, and the vsock-agent readiness probe. That's 7 files whose receivers flipped from *Daemon to *HostNetwork, plus a new host_network.go that declares the struct, its hostNetworkDeps, and the factored firecracker + DNS helpers that used to live in vm.go. Daemon gives up the tapPool and vmDNS fields entirely; they're now HostNetwork's business. Construction goes through newHostNetwork in Daemon.Open with an explicit dependency bag (runner, logger, config, layout, closing). A lazy-init hostNet() helper on Daemon supports test literals that don't wire net explicitly — production always populates it eagerly. Signature tightenings where the old receiver reached into VM-service state: - ensureNAT(ctx, vm, enable) → ensureNAT(ctx, guestIP, tap, enable). Callers resolve tap from the handle cache themselves. - initializeTapPool(ctx) → initializeTapPool(usedTaps []string). Daemon.Open enumerates VMs, collects taps from handles, hands the slice in. rebuildDNS stays on *Daemon as the orchestrator — it filters by vm-alive (a VMService concern handles will move to in phase 4) then calls HostNetwork.replaceDNS with the already-filtered map. Capability hooks continue to take *Daemon; they now use it as a facade to reach services (d.net.ensureNAT, d.hostNet().*). Planned CapabilityHost interface extraction is orthogonal, left for later. Tests: dns_routing_test.go + fastpath_test.go + nat_test.go + snapshot_test.go + open_close_test.go were touched to construct HostNetwork literals where they exercise its methods directly, or route through d.hostNet() where they exercise the Daemon entry points. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
eba9a553bf
commit
362009d747
18 changed files with 461 additions and 326 deletions
|
|
@ -52,12 +52,11 @@ type Daemon struct {
|
|||
// lives in the store, this is rebuildable from a per-VM
|
||||
// handles.json scratch file and OS inspection.
|
||||
handles *handleCache
|
||||
tapPool tapPool
|
||||
net *HostNetwork
|
||||
closing chan struct{}
|
||||
once sync.Once
|
||||
pid int
|
||||
listener net.Listener
|
||||
vmDNS *vmdns.Server
|
||||
vmCaps []vmCapability
|
||||
pullAndFlatten func(ctx context.Context, ref, cacheDir, destDir string) (imagepull.Metadata, error)
|
||||
finalizePulledRootfs func(ctx context.Context, ext4File string, meta imagepull.Metadata) error
|
||||
|
|
@ -90,15 +89,24 @@ func Open(ctx context.Context) (d *Daemon, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
closing := make(chan struct{})
|
||||
runner := system.NewRunner()
|
||||
d = &Daemon{
|
||||
layout: layout,
|
||||
config: cfg,
|
||||
store: db,
|
||||
runner: system.NewRunner(),
|
||||
runner: runner,
|
||||
logger: logger,
|
||||
closing: make(chan struct{}),
|
||||
closing: closing,
|
||||
pid: os.Getpid(),
|
||||
handles: newHandleCache(),
|
||||
net: newHostNetwork(hostNetworkDeps{
|
||||
runner: runner,
|
||||
logger: logger,
|
||||
config: cfg,
|
||||
layout: layout,
|
||||
closing: closing,
|
||||
}),
|
||||
}
|
||||
// From here on, every failure path must run Close() so the host
|
||||
// state we touched (DNS listener goroutine, resolvectl routing,
|
||||
|
|
@ -114,7 +122,7 @@ func Open(ctx context.Context) (d *Daemon, err error) {
|
|||
|
||||
d.ensureVMSSHClientConfig()
|
||||
d.logger.Info("daemon opened", "socket", layout.SocketPath, "state_dir", layout.StateDir, "log_level", cfg.LogLevel)
|
||||
if err = d.startVMDNS(vmdns.DefaultListenAddr); err != nil {
|
||||
if err = d.hostNet().startVMDNS(vmdns.DefaultListenAddr); err != nil {
|
||||
d.logger.Error("daemon open failed", "stage", "start_vm_dns", "error", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -122,12 +130,24 @@ func Open(ctx context.Context) (d *Daemon, err error) {
|
|||
d.logger.Error("daemon open failed", "stage", "reconcile", "error", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
d.ensureVMDNSResolverRouting(ctx)
|
||||
if err = d.initializeTapPool(ctx); err != nil {
|
||||
d.logger.Error("daemon open failed", "stage", "initialize_tap_pool", "error", err.Error())
|
||||
return nil, err
|
||||
d.hostNet().ensureVMDNSResolverRouting(ctx)
|
||||
// Seed HostNetwork's pool index from taps already claimed by VMs
|
||||
// on disk so newly warmed pool entries don't collide with them.
|
||||
if d.config.TapPoolSize > 0 && d.store != nil {
|
||||
vms, listErr := d.store.ListVMs(ctx)
|
||||
if listErr != nil {
|
||||
d.logger.Error("daemon open failed", "stage", "initialize_tap_pool", "error", listErr.Error())
|
||||
return nil, listErr
|
||||
}
|
||||
used := make([]string, 0, len(vms))
|
||||
for _, vm := range vms {
|
||||
if tap := d.vmHandles(vm.ID).TapDevice; tap != "" {
|
||||
used = append(used, tap)
|
||||
}
|
||||
}
|
||||
d.hostNet().initializeTapPool(used)
|
||||
}
|
||||
go d.ensureTapPool(context.Background())
|
||||
go d.hostNet().ensureTapPool(context.Background())
|
||||
return d, nil
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +161,7 @@ func (d *Daemon) Close() error {
|
|||
if d.listener != nil {
|
||||
_ = d.listener.Close()
|
||||
}
|
||||
err = errors.Join(d.clearVMDNSResolverRouting(context.Background()), d.stopVMDNS(), d.store.Close())
|
||||
err = errors.Join(d.hostNet().clearVMDNSResolverRouting(context.Background()), d.hostNet().stopVMDNS(), d.store.Close())
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
|
@ -518,27 +538,6 @@ func (d *Daemon) backgroundLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *Daemon) startVMDNS(addr string) error {
|
||||
server, err := vmdns.New(addr, d.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.vmDNS = server
|
||||
if d.logger != nil {
|
||||
d.logger.Info("vm dns serving", "dns_addr", server.Addr())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Daemon) stopVMDNS() error {
|
||||
if d.vmDNS == nil {
|
||||
return nil
|
||||
}
|
||||
err := d.vmDNS.Close()
|
||||
d.vmDNS = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Daemon) ensureDefaultImage(ctx context.Context) error {
|
||||
_ = ctx
|
||||
return nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue