diff --git a/integration/windows_hostprocess_test.go b/integration/windows_hostprocess_test.go index 4fc04738f..7346727ae 100644 --- a/integration/windows_hostprocess_test.go +++ b/integration/windows_hostprocess_test.go @@ -127,7 +127,7 @@ func runHostProcess(t *testing.T, expectErr bool, image string, action hpcAction action(t, cn, containerConfig) } -func runAndRemoveContainer(t *testing.T, sb string, sbConfig *runtime.PodSandboxConfig, cnConfig *runtime.ContainerConfig) { +func runExecAndRemoveContainer(t *testing.T, sb string, sbConfig *runtime.PodSandboxConfig, cnConfig *runtime.ContainerConfig) { t.Log("Create the container") cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) require.NoError(t, err) @@ -136,6 +136,13 @@ func runAndRemoveContainer(t *testing.T, sb string, sbConfig *runtime.PodSandbox // Wait few seconds for the container to be completely initialized time.Sleep(5 * time.Second) + cmd := []string{"cmd", "/c", "echo", "hello"} + timeoutDuration := 10 * time.Second + stdout, _, err := runtimeService.ExecSync(cn, cmd, timeoutDuration) + require.NoError(t, err) + t.Logf("Exec response: %v", stdout) + require.Equal(t, "hello\r\n", string(stdout)) + t.Log("Stop the container") require.NoError(t, runtimeService.StopContainer(cn, 0)) t.Log("Remove the container") @@ -187,6 +194,6 @@ func TestArgsEscapedImagesOnWindows(t *testing.T) { localSystemUsername, ) - runAndRemoveContainer(t, sb, sbConfig, cnConfigWithCtrCmd) - runAndRemoveContainer(t, sb, sbConfig, cnConfigNoCtrCmd) + runExecAndRemoveContainer(t, sb, sbConfig, cnConfigWithCtrCmd) + runExecAndRemoveContainer(t, sb, sbConfig, cnConfigNoCtrCmd) } diff --git a/pkg/cri/server/container_create_windows_test.go b/pkg/cri/server/container_create_windows_test.go index 4ef3a7931..9a5e11f5d 100644 --- a/pkg/cri/server/container_create_windows_test.go +++ b/pkg/cri/server/container_create_windows_test.go @@ -19,6 +19,8 @@ package server import ( "testing" + "github.com/stretchr/testify/require" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" runtimespec "github.com/opencontainers/runtime-spec/specs-go" "github.com/stretchr/testify/assert" @@ -28,6 +30,20 @@ import ( "github.com/containerd/containerd/v2/pkg/cri/config" ) +func getSandboxConfig() *runtime.PodSandboxConfig { + return &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-sandbox-name", + Uid: "test-sandbox-uid", + Namespace: "test-sandbox-ns", + Attempt: 2, + }, + Windows: &runtime.WindowsPodSandboxConfig{}, + Hostname: "test-hostname", + Annotations: map[string]string{"c": "d"}, + } +} + func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, string, uint32, *runtimespec.Spec)) { config := &runtime.ContainerConfig{ @@ -76,17 +92,7 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox }, }, } - sandboxConfig := &runtime.PodSandboxConfig{ - Metadata: &runtime.PodSandboxMetadata{ - Name: "test-sandbox-name", - Uid: "test-sandbox-uid", - Namespace: "test-sandbox-ns", - Attempt: 2, - }, - Windows: &runtime.WindowsPodSandboxConfig{}, - Hostname: "test-hostname", - Annotations: map[string]string{"c": "d"}, - } + sandboxConfig := getSandboxConfig() imageConfig := &imagespec.ImageConfig{ Env: []string{"ik1=iv1", "ik2=iv2", "ik3=iv3=iv3bis", "ik4=iv4=iv4bis=boop"}, Entrypoint: []string{"/entrypoint"}, @@ -254,3 +260,104 @@ func TestHostProcessRequirements(t *testing.T) { }) } } + +func TestEntrypointAndCmdForArgsEscaped(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + nsPath := "test-ns" + c := newTestCRIService() + + for name, test := range map[string]struct { + imgEntrypoint []string + imgCmd []string + command []string + args []string + expectedArgs []string + expectedCommandLine string + ArgsEscaped bool + }{ + // override image entrypoint and cmd in shell form with container args and verify expected runtime spec + "TestShellFormImgEntrypointCmdWithCtrArgs": { + imgEntrypoint: []string{`"C:\My Folder\MyProcess.exe" -arg1 "test value"`}, + imgCmd: []string{`cmd -args "hello world"`}, + command: nil, + args: []string{`cmd -args "additional args"`}, + expectedArgs: nil, + expectedCommandLine: `"C:\My Folder\MyProcess.exe" -arg1 "test value" "cmd -args \"additional args\""`, + ArgsEscaped: true, + }, + // check image entrypoint and cmd in shell form without overriding with container command and args and verify expected runtime spec + "TestShellFormImgEntrypointCmdWithoutCtrArgs": { + imgEntrypoint: []string{`"C:\My Folder\MyProcess.exe" -arg1 "test value"`}, + imgCmd: []string{`cmd -args "hello world"`}, + command: nil, + args: nil, + expectedArgs: nil, + expectedCommandLine: `"C:\My Folder\MyProcess.exe" -arg1 "test value" "cmd -args \"hello world\""`, + ArgsEscaped: true, + }, + // override image entrypoint and cmd by container command and args in shell form and verify expected runtime spec + "TestShellFormImgEntrypointCmdWithCtrEntrypointAndArgs": { + imgEntrypoint: []string{`"C:\My Folder\MyProcess.exe" -arg1 "test value"`}, + imgCmd: []string{`cmd -args "hello world"`}, + command: []string{`C:\My Folder\MyProcess.exe`, "-arg1", "additional test value"}, + args: []string{"cmd", "-args", "additional args"}, + expectedArgs: nil, + expectedCommandLine: `"C:\My Folder\MyProcess.exe" -arg1 "additional test value" cmd -args "additional args"`, + ArgsEscaped: true, + }, + // override image cmd by container args in exec form and verify expected runtime spec + "TestExecFormImgEntrypointCmdWithCtrArgs": { + imgEntrypoint: []string{`C:\My Folder\MyProcess.exe`, "-arg1", "test value"}, + imgCmd: []string{"cmd", "-args", "hello world"}, + command: nil, + args: []string{"additional", "args"}, + expectedArgs: []string{`C:\My Folder\MyProcess.exe`, "-arg1", "test value", "additional", "args"}, + expectedCommandLine: "", + ArgsEscaped: false, + }, + // check image entrypoint and cmd in exec form without overriding with container command and args and verify expected runtime spec + "TestExecFormImgEntrypointCmdWithoutCtrArgs": { + imgEntrypoint: []string{`C:\My Folder\MyProcess.exe`, "-arg1", "test value"}, + imgCmd: []string{"cmd", "-args", "hello world"}, + command: nil, + args: nil, + expectedArgs: []string{`C:\My Folder\MyProcess.exe`, "-arg1", "test value", "cmd", "-args", "hello world"}, + expectedCommandLine: "", + ArgsEscaped: false, + }, + } { + t.Run(name, func(t *testing.T) { + imageConfig := &imagespec.ImageConfig{ + Entrypoint: test.imgEntrypoint, + Cmd: test.imgCmd, + ArgsEscaped: test.ArgsEscaped, + } + sandboxConfig := getSandboxConfig() + containerConfig := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + Image: &runtime.ImageSpec{ + Image: testImageName, + }, + Command: test.command, + Args: test.args, + Windows: &runtime.WindowsContainerConfig{}, + } + runtimeSpec, err := c.buildContainerSpec(currentPlatform, testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{}) + assert.NoError(t, err) + assert.NotNil(t, runtimeSpec) + + // check the runtime spec for expected commandline and args + actualCommandLine := runtimeSpec.Process.CommandLine + actualArgs := runtimeSpec.Process.Args + + require.Equal(t, actualArgs, test.expectedArgs) + require.Equal(t, actualCommandLine, test.expectedCommandLine) + }) + } +}