kvm2: SSH transport, ctx-first libvirt seam, host table and span decorator

Every go-libvirt call runs under its own budget and a cancelled or overlong
call kills the connection; credentials are read on every dial; one span and
one log line per RPC come from a decorator applied where connections are
made.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-16 17:43:27 +00:00
co-authored by Claude Fable 5.1
parent 1f10a51f82
commit b45f83327a
13 changed files with 3055 additions and 10 deletions
+10 -6
View File
@@ -25,9 +25,10 @@ const (
// Provider is one configured kvm2 entry: a set of hosts sharing one SSH key
// and one image and machine-type catalogue.
type Provider struct {
name string
cfg provider.KVMConfig
now func() time.Time
name string
cfg provider.KVMConfig
now func() time.Time
hosts *hostTable
}
var _ provider.Provider = (*Provider)(nil)
@@ -40,7 +41,8 @@ func New(ctx context.Context, pc provider.ProviderConfig) (provider.Provider, er
if pc.KVM2 != nil {
cfg = *pc.KVM2
}
p := newProvider(pc.Name, cfg)
cfg = withDefaults(cfg)
p := newProvider(pc.Name, cfg, newLibvirtDialer(pc.Name, cfg))
log := p.logger(ctx)
if _, err := os.Stat(p.cfg.SSHKeyFile); err != nil {
log.Info("WARNING: ssh key file is not readable; every call fails until it is", "path", p.cfg.SSHKeyFile, "reason", err.Error())
@@ -56,8 +58,10 @@ func New(ctx context.Context, pc provider.ProviderConfig) (provider.Provider, er
return p, nil
}
func newProvider(name string, cfg provider.KVMConfig) *Provider {
return &Provider{name: name, cfg: withDefaults(cfg), now: time.Now}
// newProvider is the constructor tests use: d hands out the backends, the
// production one being newLibvirtDialer.
func newProvider(name string, cfg provider.KVMConfig, d dialer) *Provider {
return &Provider{name: name, cfg: withDefaults(cfg), now: time.Now, hosts: newHostTable(d)}
}
// withDefaults returns cfg with every optional field filled in, so the rest