Set SystemTemp env var to config temp on Windows

Since Go 1.21, os.MkdirTemp/os.TempDir resolve the temp directory via
Windows' GetTempPath2W. For processes running as SYSTEM (as containerd
does when running under the SCM), that API reads the temp location from
the SystemTemp environment variable rather than TMP/TEMP. As a result,
the existing TMP/TEMP overrides no longer steer the layer-extraction
tempdir for the containerd service, so it falls back to the default
C:\\Windows\\SystemTemp and unpacks on the SystemDrive, reintroducing the
cross-volume copy the 'temp' config option was meant to avoid.

Set SystemTemp to config.TempDir alongside TEMP/TMP so the override keeps
working on Go 1.21+.

Factor the env-var setting out of CreateTopLevelDirectories into a small
setTempDirEnv helper and add a focused unit test (TestSetTempDirEnv) that
verifies the expected variables are set: TEMP/TMP/SystemTemp on Windows,
TMPDIR on other platforms.

Ref: https://cs.opensource.google/go/go/+/refs/tags/go1.21.0:src/os/file_windows.go
Signed-off-by: Maksim An <maksiman@microsoft.com>
This commit is contained in:
Maksim An
2026-06-25 00:49:19 -07:00
committed by k8s-infra-cherrypick-robot
parent 6c0e7e9bae
commit 26dce170df
2 changed files with 47 additions and 12 deletions

View File

@@ -92,22 +92,34 @@ func CreateTopLevelDirectories(config *srvconfig.Config) error {
if err := os.Chmod(config.TempDir, 0o700); err != nil && !errors.Is(err, os.ErrPermission) {
return err
}
if runtime.GOOS == "windows" {
// On Windows, the Host Compute Service (vmcompute) will read the
// TEMP/TMP setting from the calling process when creating the
// tempdir to extract an image layer to. This allows the
// administrator to align the tempdir location with the same volume
// as the snapshot dir to avoid a copy operation when moving the
// extracted layer to the snapshot dir location.
os.Setenv("TEMP", config.TempDir)
os.Setenv("TMP", config.TempDir)
} else {
os.Setenv("TMPDIR", config.TempDir)
}
setTempDirEnv(config.TempDir)
}
return nil
}
// setTempDirEnv points the process' temp-directory environment variables at
// tempDir so that components (and the OS) honor the configured temp location.
func setTempDirEnv(tempDir string) {
if runtime.GOOS == "windows" {
// On Windows, the Host Compute Service (vmcompute) will read the
// TEMP/TMP setting from the calling process when creating the
// tempdir to extract an image layer to. This allows the
// administrator to align the tempdir location with the same volume
// as the snapshot dir to avoid a copy operation when moving the
// extracted layer to the snapshot dir location.
os.Setenv("TEMP", tempDir)
os.Setenv("TMP", tempDir)
// Since Go 1.21, os.MkdirTemp/os.TempDir resolve the temp dir via
// Windows' GetTempPath2W. For processes running as SYSTEM (as
// containerd does under the SCM), that API reads SystemTemp rather
// than TEMP/TMP, so set it too to keep the override effective.
// https://cs.opensource.google/go/go/+/refs/tags/go1.21.0:src/os/file_windows.go
os.Setenv("SystemTemp", tempDir)
} else {
os.Setenv("TMPDIR", tempDir)
}
}
// New creates and initializes a new containerd server
func New(ctx context.Context, config *srvconfig.Config) (*Server, error) {
if err := apply(ctx, config); err != nil {

View File

@@ -20,6 +20,7 @@ import (
"context"
"iter"
"os"
"runtime"
"slices"
"testing"
@@ -172,3 +173,25 @@ func TestMigration(t *testing.T) {
t.Fatal(err)
}
}
func TestSetTempDirEnv(t *testing.T) {
const tempDir = "/tmp/path/for/testing/temp"
var keys []string
if runtime.GOOS == "windows" {
keys = []string{"TEMP", "TMP", "SystemTemp"}
} else {
keys = []string{"TMPDIR"}
}
for _, k := range keys {
t.Setenv(k, "")
}
setTempDirEnv(tempDir)
for _, k := range keys {
if got := os.Getenv(k); got != tempDir {
t.Errorf("expected %s=%q, got %q", k, tempDir, got)
}
}
}