mirror of https://github.com/coder/coder.git
fix: use raw syscalls to write binary we execute (#11684)
Fixes flake seen here, I think https://github.com/coder/coder/actions/runs/7565915337/job/20602500818 golang's file processing is complex, and in at least some cases it can return from a file.Close() call without having actually closed the file descriptor. If we're holding open the file descriptor of an executable we just wrote, and try to execute it, it will fail with "text file busy" which is what we have seen. So, to be extra sure, I've avoided the standard library and directly called the syscalls to open, write, and close the file we intend to use in the test. I've also added some more logging so if it's some issue of multiple tests writing to the same location, the we might have a chance to see it.
This commit is contained in:
parent
c5d73b86d6
commit
1f0e6ba6c6
|
@ -123,6 +123,10 @@ func (e *executor) execParseJSON(ctx, killCtx context.Context, args, env []strin
|
|||
cmd.Stdout = out
|
||||
cmd.Stderr = stdErr
|
||||
|
||||
e.server.logger.Debug(ctx, "executing terraform command with JSON result",
|
||||
slog.F("binary_path", e.binaryPath),
|
||||
slog.F("args", args),
|
||||
)
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -348,6 +352,10 @@ func (e *executor) graph(ctx, killCtx context.Context) (string, error) {
|
|||
cmd.Dir = e.workdir
|
||||
cmd.Env = e.basicEnv()
|
||||
|
||||
e.server.logger.Debug(ctx, "executing terraform command graph",
|
||||
slog.F("binary_path", e.binaryPath),
|
||||
slog.F("args", "graph"),
|
||||
)
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -165,8 +166,18 @@ func TestProvision_Cancel(t *testing.T) {
|
|||
|
||||
// Example: exec /path/to/terrafork_fake_cancel.sh 1.2.1 apply "$@"
|
||||
content := fmt.Sprintf("#!/bin/sh\nexec %q %s %s \"$@\"\n", fakeBin, terraform.TerraformVersion.String(), tt.mode)
|
||||
err := os.WriteFile(binPath, []byte(content), 0o755) //#nosec
|
||||
|
||||
// golang's standard OS library can sometimes leave the file descriptor open even after
|
||||
// "Closing" the file (which can then lead to a "text file busy" error, so we bypass this
|
||||
// and use syscall directly).
|
||||
fd, err := syscall.Open(binPath, syscall.O_WRONLY|syscall.O_CREAT, 0o755)
|
||||
require.NoError(t, err)
|
||||
n, err := syscall.Write(fd, []byte(content))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(content), n)
|
||||
err = syscall.Close(fd)
|
||||
require.NoError(t, err)
|
||||
t.Logf("wrote fake terraform script to %s", binPath)
|
||||
|
||||
ctx, api := setupProvisioner(t, &provisionerServeOptions{
|
||||
binaryPath: binPath,
|
||||
|
|
Loading…
Reference in New Issue