Give the manager a writable /tmp for seed ISOs; keep the libvirt connection on classified errors

The manager runs with a read-only root filesystem and the seed ISO
writer stages files in a temp directory, so the first in-cluster Create
failed with "creating iso writer: read-only file system". Mount a 64 MiB
emptyDir on /tmp.

That error is classified ErrPermanent by writeSeed, yet hostPool.call
treated every non-libvirt error as a transport failure and dropped the
cached SSH connection, redialling on each retry. Errors that already
carry a provider sentinel are local verdicts, not evidence about the
link; leave the connection alone for those.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 21:06:34 +00:00
co-authored by Claude Fable 5.1
parent c5ebb2e044
commit 220967660d
4 changed files with 51 additions and 5 deletions
+23
View File
@@ -7,6 +7,7 @@ import (
"crypto/rand"
"encoding/pem"
"errors"
"fmt"
"io"
"net"
"os"
@@ -652,3 +653,25 @@ func TestHostPool_call_logsDropReason(t *testing.T) {
}
})
}
func TestHostPool_call_keepsConnectionOnClassifiedError(t *testing.T) {
t.Parallel()
d := &fakeDialer{}
p := newHostPool(d.dial)
log, snapshot := captureLogger(1)
err := p.call(context.Background(), log, testHost, func(libvirtAPI) error {
return fmt.Errorf("%w: creating iso writer: read-only file system", provider.ErrPermanent)
})
if !errors.Is(err, provider.ErrPermanent) {
t.Fatalf("call() error = %v, want the classified error passed through", err)
}
if d.clients[0].closed.Load() {
t.Error("connection closed after a locally classified error; only transport errors should drop it")
}
if joined := strings.Join(snapshot(), "\n"); strings.Contains(joined, "connection dropped") {
t.Errorf("drop logged for a local error:\n%s", joined)
}
if err := p.call(context.Background(), log, testHost, noop); err != nil || d.dialCount() != 1 {
t.Errorf("next call redialled (dials=%d, err=%v), want the cached connection reused", d.dialCount(), err)
}
}