Simplify the KVM provider after the /simplify review
Collapse duplicated logic the review found in PR #5 without changing behaviour: one releaseFinalizer helper for the four finalizer exits in reconcileDelete, classify reusing isClassified and provider.Class, the image URL check and format/firmware values shared from the provider package, imageSource and the metadata parser embedding their config structs instead of copying fields, and the SSH loader as a small struct that keeps only the SSH fields and is seeded by New instead of loading the key twice. Tracing builds its V(2)-only lists only at V(2). Tests: drop a duplicate New test, fold near-identical tests into tables (connection drops, metadata parsing, cached images), add mustSSHAuth, and use wantClass where classes were checked by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -95,7 +95,8 @@ func testConfig(hosts ...string) provider.ProviderConfig {
|
||||
}
|
||||
|
||||
func newTestProvider(fakes hostFakes, hosts ...string) *Provider {
|
||||
p := newWithDialer(testConfig(hosts...), fakes.dial, nil)
|
||||
pc := testConfig(hosts...)
|
||||
p := newWithDialer(pc.Name, *pc.KVM, fakes.dial, nil)
|
||||
p.now = func() time.Time { return testNow }
|
||||
return p
|
||||
}
|
||||
@@ -103,7 +104,7 @@ func newTestProvider(fakes hostFakes, hosts ...string) *Provider {
|
||||
// cacheImage pre-populates the pool with the configured image and its
|
||||
// marker so Create never touches the network.
|
||||
func cacheImage(api *fakeAPI) {
|
||||
src := imageSource{Key: "debian-13", URL: testImageURL, Format: formatQcow2}
|
||||
src := imageSource{Key: "debian-13", KVMImage: provider.KVMImage{URL: testImageURL, Format: formatQcow2}}
|
||||
api.putVol("default", src.volumeName(), formatQcow2, []byte("qcow2"))
|
||||
api.putVol("default", src.markerName(), formatRaw, []byte(testImageSHA()))
|
||||
}
|
||||
@@ -241,7 +242,7 @@ func TestCreate_fetchesImageOnFirstUse(t *testing.T) {
|
||||
api := newFakeAPI("default")
|
||||
cfg := testConfig("nas1")
|
||||
cfg.KVM.Images["debian-13"] = provider.KVMImage{URL: srv.URL + "/debian.qcow2", SHA256: testImageSHA()}
|
||||
p := newWithDialer(cfg, hostFakes{"nas1": api}.dial, nil)
|
||||
p := newWithDialer(cfg.Name, *cfg.KVM, hostFakes{"nas1": api}.dial, nil)
|
||||
|
||||
if _, err := p.Create(context.Background(), testRequest()); err != nil {
|
||||
t.Fatalf("Create: %v", err)
|
||||
@@ -479,28 +480,25 @@ func TestCreate_hostFailures(t *testing.T) {
|
||||
t.Parallel()
|
||||
cases := []struct {
|
||||
name string
|
||||
setup func() (hostFakes, string)
|
||||
setup func() hostFakes
|
||||
class error
|
||||
}{
|
||||
{
|
||||
name: "host unreachable",
|
||||
setup: func() (hostFakes, string) { return hostFakes{}, "nas1" },
|
||||
setup: func() hostFakes { return hostFakes{} },
|
||||
class: provider.ErrTransient,
|
||||
},
|
||||
{
|
||||
name: "pool missing",
|
||||
setup: func() (hostFakes, string) {
|
||||
api := newFakeAPI("other")
|
||||
return hostFakes{"nas1": api}, "nas1"
|
||||
},
|
||||
name: "pool missing",
|
||||
setup: func() hostFakes { return hostFakes{"nas1": newFakeAPI("other")} },
|
||||
class: provider.ErrPermanent,
|
||||
},
|
||||
{
|
||||
name: "domain xml rejected",
|
||||
setup: func() (hostFakes, string) {
|
||||
setup: func() hostFakes {
|
||||
api := readyHost()
|
||||
api.fail["DomainDefineXML"] = lvError(libvirt.ErrConfigUnsupported, "no q35 here")
|
||||
return hostFakes{"nas1": api}, "nas1"
|
||||
return hostFakes{"nas1": api}
|
||||
},
|
||||
class: provider.ErrPermanent,
|
||||
},
|
||||
@@ -508,8 +506,7 @@ func TestCreate_hostFailures(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
fakes, host := tc.setup()
|
||||
p := newTestProvider(fakes, host)
|
||||
p := newTestProvider(tc.setup(), "nas1")
|
||||
_, err := p.Create(context.Background(), testRequest())
|
||||
wantClass(t, err, tc.class)
|
||||
})
|
||||
@@ -747,9 +744,8 @@ func TestDelete_unconfiguredHostIsNotAnError(t *testing.T) {
|
||||
}
|
||||
// Get still refuses, so the live path cannot mistake a config typo for a
|
||||
// missing VM and recreate it somewhere else.
|
||||
if _, err := p.Get(context.Background(), "hosts/nas9/domains/"+testName); provider.Class(err) != provider.ErrPermanent {
|
||||
t.Errorf("Get class = %v, want ErrPermanent", provider.Class(err))
|
||||
}
|
||||
_, err := p.Get(context.Background(), "hosts/nas9/domains/"+testName)
|
||||
wantClass(t, err, provider.ErrPermanent)
|
||||
}
|
||||
|
||||
func TestDelete_errors(t *testing.T) {
|
||||
@@ -909,23 +905,6 @@ func TestMapState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A bad key path no longer fails the constructor: registry.Build aborts the
|
||||
// whole provider set on a constructor error, so that took the manager down
|
||||
// with every other provider. It degrades per-proxy instead — see
|
||||
// TestNew_missingSSHMaterialStillBuilds and TestLazyAuth_healsWhenTheKeyAppears.
|
||||
func TestNew_badKeyPathDefersToFirstUse(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := testConfig("nas1")
|
||||
cfg.KVM.SSHKeyFile = t.TempDir() + "/missing"
|
||||
p, err := New(context.Background(), cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error = %v, want a provider that fails only when used", err)
|
||||
}
|
||||
if err := p.Delete(context.Background(), "hosts/nas1/domains/proxy-x"); provider.Class(err) != provider.ErrTransient {
|
||||
t.Errorf("Delete class = %v, want ErrTransient", provider.Class(err))
|
||||
}
|
||||
}
|
||||
|
||||
// runAllOps drives one full lifecycle over a ready fake host so logging
|
||||
// tests see every provider method and every libvirt call.
|
||||
func runAllOps(t *testing.T, ctx context.Context, req provider.CreateRequest) {
|
||||
|
||||
Reference in New Issue
Block a user