Skip to content

Commit 702cea2

Browse files
authored
Merge pull request kubernetes#123952 from kinvolk/rata/userns-add-tests-namespacesForPod
pkg/kubelet/kuberuntime: Add userns tests for NamespacesForPod
2 parents 1ecb491 + 6f81aa6 commit 702cea2

File tree

2 files changed

+132
-6
lines changed

2 files changed

+132
-6
lines changed

pkg/kubelet/container/testing/fake_runtime_helper.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ package testing
1818

1919
import (
2020
"context"
21+
"fmt"
2122

2223
v1 "k8s.io/api/core/v1"
2324
kubetypes "k8s.io/apimachinery/pkg/types"
25+
utilfeature "k8s.io/apiserver/pkg/util/feature"
2426
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
27+
"k8s.io/kubernetes/pkg/features"
2528
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
2629
)
2730

@@ -33,6 +36,7 @@ type FakeRuntimeHelper struct {
3336
HostName string
3437
HostDomain string
3538
PodContainerDir string
39+
RuntimeHandlers map[string]kubecontainer.RuntimeHandler
3640
Err error
3741
}
3842

@@ -69,7 +73,38 @@ func (f *FakeRuntimeHelper) GetExtraSupplementalGroupsForPod(pod *v1.Pod) []int6
6973
}
7074

7175
func (f *FakeRuntimeHelper) GetOrCreateUserNamespaceMappings(pod *v1.Pod, runtimeHandler string) (*runtimeapi.UserNamespace, error) {
72-
return nil, nil
76+
featureEnabled := utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesSupport)
77+
if pod == nil || pod.Spec.HostUsers == nil {
78+
return nil, nil
79+
}
80+
// pod.Spec.HostUsers is set to true/false
81+
if !featureEnabled {
82+
return nil, fmt.Errorf("the feature gate %q is disabled: can't set spec.HostUsers", features.UserNamespacesSupport)
83+
}
84+
if *pod.Spec.HostUsers {
85+
return nil, nil
86+
}
87+
88+
// From here onwards, hostUsers=false and the feature gate is enabled.
89+
90+
// if the pod requested a user namespace and the runtime doesn't support user namespaces then return an error.
91+
if h, ok := f.RuntimeHandlers[runtimeHandler]; !ok {
92+
return nil, fmt.Errorf("RuntimeClass handler %q not found", runtimeHandler)
93+
} else if !h.SupportsUserNamespaces {
94+
return nil, fmt.Errorf("RuntimeClass handler %q does not support user namespaces", runtimeHandler)
95+
}
96+
97+
ids := &runtimeapi.IDMapping{
98+
HostId: 65536,
99+
ContainerId: 0,
100+
Length: 65536,
101+
}
102+
103+
return &runtimeapi.UserNamespace{
104+
Mode: runtimeapi.NamespaceMode_POD,
105+
Uids: []*runtimeapi.IDMapping{ids},
106+
Gids: []*runtimeapi.IDMapping{ids},
107+
}, nil
73108
}
74109

75110
func (f *FakeRuntimeHelper) PrepareDynamicResources(pod *v1.Pod) error {

pkg/kubelet/kuberuntime/util/util_test.go

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import (
2222
"github.com/stretchr/testify/require"
2323

2424
v1 "k8s.io/api/core/v1"
25+
utilfeature "k8s.io/apiserver/pkg/util/feature"
26+
featuregatetesting "k8s.io/component-base/featuregate/testing"
2527
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
28+
pkgfeatures "k8s.io/kubernetes/pkg/features"
2629
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
2730
kubecontainertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
2831
)
@@ -162,10 +165,25 @@ func TestPodSandboxChanged(t *testing.T) {
162165
}
163166
}
164167

168+
type fakeRuntimeHandlerResolver struct{}
169+
170+
func (*fakeRuntimeHandlerResolver) LookupRuntimeHandler(s *string) (string, error) {
171+
return "", nil
172+
}
173+
165174
func TestNamespacesForPod(t *testing.T) {
175+
usernsIDs := &runtimeapi.IDMapping{
176+
HostId: 65536,
177+
ContainerId: 0,
178+
Length: 65536,
179+
}
180+
166181
for desc, test := range map[string]struct {
167-
input *v1.Pod
168-
expected *runtimeapi.NamespaceOption
182+
input *v1.Pod
183+
runtimeHandlers map[string]kubecontainer.RuntimeHandler
184+
usernsEnabled bool
185+
expected *runtimeapi.NamespaceOption
186+
expErr bool
169187
}{
170188
"nil pod -> default v1 namespaces": {
171189
input: nil,
@@ -221,11 +239,84 @@ func TestNamespacesForPod(t *testing.T) {
221239
Pid: runtimeapi.NamespaceMode_CONTAINER,
222240
},
223241
},
242+
"hostUsers: false and feature enabled": {
243+
input: &v1.Pod{
244+
Spec: v1.PodSpec{
245+
HostUsers: &[]bool{false}[0],
246+
},
247+
},
248+
usernsEnabled: true,
249+
runtimeHandlers: map[string]kubecontainer.RuntimeHandler{
250+
"": {
251+
SupportsUserNamespaces: true,
252+
},
253+
},
254+
expected: &runtimeapi.NamespaceOption{
255+
Ipc: runtimeapi.NamespaceMode_POD,
256+
Network: runtimeapi.NamespaceMode_POD,
257+
Pid: runtimeapi.NamespaceMode_CONTAINER,
258+
UsernsOptions: &runtimeapi.UserNamespace{
259+
Mode: runtimeapi.NamespaceMode_POD,
260+
Uids: []*runtimeapi.IDMapping{usernsIDs},
261+
Gids: []*runtimeapi.IDMapping{usernsIDs},
262+
},
263+
},
264+
},
265+
// The hostUsers field can't be set to any value if the feature is disabled.
266+
"hostUsers: false and feature disabled --> error": {
267+
input: &v1.Pod{
268+
Spec: v1.PodSpec{
269+
HostUsers: &[]bool{false}[0],
270+
},
271+
},
272+
usernsEnabled: false,
273+
expErr: true,
274+
},
275+
// The hostUsers field can't be set to any value if the feature is disabled.
276+
"hostUsers: true and feature disabled --> error": {
277+
input: &v1.Pod{
278+
Spec: v1.PodSpec{
279+
HostUsers: &[]bool{true}[0],
280+
},
281+
},
282+
usernsEnabled: false,
283+
expErr: true,
284+
},
285+
"error if runtime handler not found": {
286+
input: &v1.Pod{
287+
Spec: v1.PodSpec{
288+
HostUsers: &[]bool{false}[0],
289+
},
290+
},
291+
usernsEnabled: true,
292+
runtimeHandlers: map[string]kubecontainer.RuntimeHandler{
293+
"other": {},
294+
},
295+
expErr: true,
296+
},
297+
"error if runtime handler does not support userns": {
298+
input: &v1.Pod{
299+
Spec: v1.PodSpec{
300+
HostUsers: &[]bool{false}[0],
301+
},
302+
},
303+
usernsEnabled: true,
304+
expErr: true,
305+
},
224306
} {
225307
t.Run(desc, func(t *testing.T) {
226-
actual, err := NamespacesForPod(test.input, &kubecontainertest.FakeRuntimeHelper{}, nil)
227-
require.NoError(t, err)
228-
require.Equal(t, test.expected, actual)
308+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.UserNamespacesSupport, test.usernsEnabled)
309+
310+
fakeRuntimeHelper := kubecontainertest.FakeRuntimeHelper{
311+
RuntimeHandlers: test.runtimeHandlers,
312+
}
313+
actual, err := NamespacesForPod(test.input, &fakeRuntimeHelper, &fakeRuntimeHandlerResolver{})
314+
if test.expErr {
315+
require.Error(t, err)
316+
} else {
317+
require.NoError(t, err)
318+
require.Equal(t, test.expected, actual)
319+
}
229320
})
230321
}
231322
}

0 commit comments

Comments
 (0)