tstest/natlab/vmtest: serialize ensureDebugSSHKey across parallel boots
Env.Start boots all VM nodes in parallel; each calls createCloudInitISO -> ensureDebugSSHKey concurrently. When /tmp/vmtest_key doesn't yet exist, the first goroutine creates it with os.WriteFile, which opens with O_CREATE|O_TRUNC and briefly leaves the file existing-but-empty between the open and the subsequent write. A concurrent goroutine that hits that window sees ReadFile succeed with zero bytes, then fails ssh.ParsePrivateKey with "ssh: no key found", causing boot to fail with: boot: creating cloud-init ISO: parse /tmp/vmtest_key: ssh: no key found Observed in CI on TestSiteToSite (3 nodes). Wrap the function in a package-level Mutex so the first caller fully writes the key before any other caller reads it. Updates #20228 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: Ie6399dcba0c397bb8041931d3de1c6063a11c568
This commit is contained in:
committed by
Brad Fitzpatrick
parent
0bc0cb8131
commit
8dde9b725b
@@ -12,6 +12,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/creachadair/mds/shell"
|
"github.com/creachadair/mds/shell"
|
||||||
"github.com/kdomanski/iso9660"
|
"github.com/kdomanski/iso9660"
|
||||||
@@ -214,7 +215,16 @@ func tailscaledEnvPrefix(n *Node) string {
|
|||||||
return strings.Join(parts, " ") + " "
|
return strings.Join(parts, " ") + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debugSSHKeyMu serializes ensureDebugSSHKey calls. Env.Start boots all
|
||||||
|
// nodes in parallel and each calls createCloudInitISO -> ensureDebugSSHKey,
|
||||||
|
// which would otherwise race on creating /tmp/vmtest_key: one goroutine
|
||||||
|
// can observe a newly-created-but-still-empty key file written by another
|
||||||
|
// and fail to parse it.
|
||||||
|
var debugSSHKeyMu sync.Mutex
|
||||||
|
|
||||||
func ensureDebugSSHKey() error {
|
func ensureDebugSSHKey() error {
|
||||||
|
debugSSHKeyMu.Lock()
|
||||||
|
defer debugSSHKeyMu.Unlock()
|
||||||
const keyPath = "/tmp/vmtest_key"
|
const keyPath = "/tmp/vmtest_key"
|
||||||
if privPEM, err := os.ReadFile(keyPath); err == nil {
|
if privPEM, err := os.ReadFile(keyPath); err == nil {
|
||||||
if _, err := os.Stat(keyPath + ".pub"); err == nil {
|
if _, err := os.Stat(keyPath + ".pub"); err == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user