Skip to content

Commit 5162238

Browse files
authored
Merge pull request containerd#5853 from claudiubelu/integration/windows-hostprocess
integration: Adds Windows HostProcess tests
2 parents f40df65 + f425131 commit 5162238

File tree

4 files changed

+133
-9
lines changed

4 files changed

+133
-9
lines changed

integration/main_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,17 @@ func PodSandboxConfigWithCleanup(t *testing.T, name, ns string, opts ...PodSandb
192192
return sb, sbConfig
193193
}
194194

195+
// Set Windows HostProcess.
196+
func WithWindowsHostProcess(p *runtime.PodSandboxConfig) { //nolint:unused
197+
if p.Windows == nil {
198+
p.Windows = &runtime.WindowsPodSandboxConfig{}
199+
}
200+
if p.Windows.SecurityContext == nil {
201+
p.Windows.SecurityContext = &runtime.WindowsSandboxSecurityContext{}
202+
}
203+
p.Windows.SecurityContext.HostProcess = true
204+
}
205+
195206
// ContainerOpts to set any specific attribute like labels,
196207
// annotations, metadata etc
197208
type ContainerOpts func(*runtime.ContainerConfig)
@@ -227,6 +238,18 @@ func WithVolumeMount(hostPath, containerPath string) ContainerOpts {
227238
}
228239
}
229240

241+
func WithWindowsUsername(username string) ContainerOpts { //nolint:unused
242+
return func(c *runtime.ContainerConfig) {
243+
if c.Windows == nil {
244+
c.Windows = &runtime.WindowsContainerConfig{}
245+
}
246+
if c.Windows.SecurityContext == nil {
247+
c.Windows.SecurityContext = &runtime.WindowsContainerSecurityContext{}
248+
}
249+
c.Windows.SecurityContext.RunAsUsername = username
250+
}
251+
}
252+
230253
// Add container command.
231254
func WithCommand(cmd string, args ...string) ContainerOpts {
232255
return func(c *runtime.ContainerConfig) {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//go:build windows
2+
// +build windows
3+
4+
/*
5+
Copyright The containerd Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package integration
21+
22+
import (
23+
"fmt"
24+
"os"
25+
"testing"
26+
27+
"github.com/stretchr/testify/assert"
28+
"github.com/stretchr/testify/require"
29+
)
30+
31+
var (
32+
defaultCommand = WithCommand("Powershell", "/c", "$env:CONTAINER_SANDBOX_MOUNT_POINT/pause.exe")
33+
localServiceUsername = WithWindowsUsername("NT AUTHORITY\\Local service")
34+
localSystemUsername = WithWindowsUsername("NT AUTHORITY\\System")
35+
)
36+
37+
// Tests to verify the Windows HostProcess
38+
func TestWindowsHostProcess(t *testing.T) {
39+
EnsureImageExists(t, pauseImage)
40+
41+
t.Run("run as Local Service", func(t *testing.T) {
42+
runHostProcess(t, false, pauseImage, localServiceUsername, defaultCommand)
43+
})
44+
t.Run("run as Local System", func(t *testing.T) {
45+
runHostProcess(t, false, pauseImage, localSystemUsername, defaultCommand)
46+
})
47+
t.Run("run as unacceptable user", func(t *testing.T) {
48+
runHostProcess(t, true, pauseImage, WithWindowsUsername("Guest"), defaultCommand)
49+
})
50+
t.Run("run command on host", func(t *testing.T) {
51+
cmd := WithCommand("Powershell", "/c", "Get-Command containerd.exe")
52+
runHostProcess(t, false, pauseImage, localServiceUsername, cmd)
53+
})
54+
t.Run("run withHostNetwork", func(t *testing.T) {
55+
hostname, err := os.Hostname()
56+
require.NoError(t, err)
57+
cmd := WithCommand("Powershell", "/c", fmt.Sprintf("if ($env:COMPUTERNAME -ne %s) { exit -1 }", hostname))
58+
runHostProcess(t, false, pauseImage, localServiceUsername, cmd)
59+
})
60+
t.Run("run with a different os.version image", func(t *testing.T) {
61+
image := "docker.io/e2eteam/busybox:1.29-windows-amd64-1909"
62+
EnsureImageExists(t, image)
63+
runHostProcess(t, false, image, localServiceUsername, defaultCommand)
64+
})
65+
}
66+
67+
func runHostProcess(t *testing.T, expectErr bool, image string, opts ...ContainerOpts) {
68+
t.Logf("Create a pod config and run sandbox container")
69+
sb, sbConfig := PodSandboxConfigWithCleanup(t, "sandbox1", "hostprocess", WithWindowsHostProcess)
70+
71+
t.Logf("Create a container config and run container in a pod")
72+
containerConfig := ContainerConfig(
73+
"container1",
74+
image,
75+
opts...,
76+
)
77+
cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig)
78+
require.NoError(t, err)
79+
defer func() {
80+
assert.NoError(t, runtimeService.RemoveContainer(cn))
81+
}()
82+
_, err = t, runtimeService.StartContainer(cn)
83+
if err != nil {
84+
if !expectErr {
85+
t.Fatalf("Unexpected error while starting Container: %v", err)
86+
}
87+
return
88+
}
89+
defer func() {
90+
assert.NoError(t, runtimeService.StopContainer(cn, 10))
91+
}()
92+
}

script/test/cri-integration.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ ${sudo} bin/cri-integration.test --test.run="${FOCUS}" --test.v \
4444
--cri-root="${CRI_ROOT}" \
4545
--runtime-handler="${RUNTIME}" \
4646
--containerd-bin="${CONTAINERD_BIN}" \
47-
--image-list="${TEST_IMAGE_LIST:-}"
48-
49-
test_exit_code=$?
47+
--image-list="${TEST_IMAGE_LIST:-}" && test_exit_code=$? || test_exit_code=$?
5048

5149
exit ${test_exit_code}

script/test/utils.sh

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,21 @@ test_setup() {
9696
set -m
9797
# Create containerd in a different process group
9898
# so that we can easily clean them up.
99-
keepalive "${sudo} bin/containerd ${CONTAINERD_FLAGS}" \
100-
"${RESTART_WAIT_PERIOD}" &> "${report_dir}/containerd.log" &
101-
pid=$!
99+
if [ $IS_WINDOWS -eq 0 ]; then
100+
keepalive "${sudo} bin/containerd ${CONTAINERD_FLAGS}" \
101+
"${RESTART_WAIT_PERIOD}" &> "${report_dir}/containerd.log" &
102+
pid=$!
103+
else
104+
# NOTE(claudiub): For Windows HostProcess containers, containerd needs to be privileged enough to
105+
# start them. For this, we can register containerd as a service, so the LocalSystem will run it
106+
# for us. Additionally, we don't need to worry about keeping it alive, Windows will do it for us.
107+
nssm install containerd-test "$(pwd)/bin/containerd.exe" ${CONTAINERD_FLAGS} \
108+
--log-file "${report_dir}/containerd.log"
109+
110+
# it might still result in SERVICE_START_PENDING, but we can ignore it.
111+
nssm start containerd-test || true
112+
pid="1" # for teardown
113+
fi
102114
set +m
103115

104116
# Wait for containerd to be running by using the containerd client ctr to check the version
@@ -116,9 +128,8 @@ test_setup() {
116128
test_teardown() {
117129
if [ -n "${pid}" ]; then
118130
if [ $IS_WINDOWS -eq 1 ]; then
119-
# NOTE(claudiub): The containerd process will have the same PGID as the keepalive process,
120-
# so we can kill both of them by matching the PGID.
121-
${sudo} ps | awk "{if (\$3 == ${pid}) print \$1}" | xargs kill
131+
nssm stop containerd-test
132+
nssm remove containerd-test confirm
122133
else
123134
${sudo} pkill -g $(ps -o pgid= -p "${pid}")
124135
fi

0 commit comments

Comments
 (0)