Merge pull request #123952 from kinvolk/rata/userns-add-tests-namespacesForPod

pkg/kubelet/kuberuntime: Add userns tests for NamespacesForPod
This commit is contained in:
Kubernetes Prow Robot 2024-08-14 04:23:22 -07:00 committed by GitHub
commit 702cea241d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 132 additions and 6 deletions

View File

@ -18,10 +18,13 @@ package testing
import (
"context"
"fmt"
v1 "k8s.io/api/core/v1"
kubetypes "k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
"k8s.io/kubernetes/pkg/features"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
)
@ -33,6 +36,7 @@ type FakeRuntimeHelper struct {
HostName string
HostDomain string
PodContainerDir string
RuntimeHandlers map[string]kubecontainer.RuntimeHandler
Err error
}
@ -69,7 +73,38 @@ func (f *FakeRuntimeHelper) GetExtraSupplementalGroupsForPod(pod *v1.Pod) []int6
}
func (f *FakeRuntimeHelper) GetOrCreateUserNamespaceMappings(pod *v1.Pod, runtimeHandler string) (*runtimeapi.UserNamespace, error) {
return nil, nil
featureEnabled := utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesSupport)
if pod == nil || pod.Spec.HostUsers == nil {
return nil, nil
}
// pod.Spec.HostUsers is set to true/false
if !featureEnabled {
return nil, fmt.Errorf("the feature gate %q is disabled: can't set spec.HostUsers", features.UserNamespacesSupport)
}
if *pod.Spec.HostUsers {
return nil, nil
}
// From here onwards, hostUsers=false and the feature gate is enabled.
// if the pod requested a user namespace and the runtime doesn't support user namespaces then return an error.
if h, ok := f.RuntimeHandlers[runtimeHandler]; !ok {
return nil, fmt.Errorf("RuntimeClass handler %q not found", runtimeHandler)
} else if !h.SupportsUserNamespaces {
return nil, fmt.Errorf("RuntimeClass handler %q does not support user namespaces", runtimeHandler)
}
ids := &runtimeapi.IDMapping{
HostId: 65536,
ContainerId: 0,
Length: 65536,
}
return &runtimeapi.UserNamespace{
Mode: runtimeapi.NamespaceMode_POD,
Uids: []*runtimeapi.IDMapping{ids},
Gids: []*runtimeapi.IDMapping{ids},
}, nil
}
func (f *FakeRuntimeHelper) PrepareDynamicResources(pod *v1.Pod) error {

View File

@ -22,7 +22,10 @@ import (
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
pkgfeatures "k8s.io/kubernetes/pkg/features"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
kubecontainertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
)
@ -162,10 +165,25 @@ func TestPodSandboxChanged(t *testing.T) {
}
}
type fakeRuntimeHandlerResolver struct{}
func (*fakeRuntimeHandlerResolver) LookupRuntimeHandler(s *string) (string, error) {
return "", nil
}
func TestNamespacesForPod(t *testing.T) {
usernsIDs := &runtimeapi.IDMapping{
HostId: 65536,
ContainerId: 0,
Length: 65536,
}
for desc, test := range map[string]struct {
input *v1.Pod
expected *runtimeapi.NamespaceOption
input *v1.Pod
runtimeHandlers map[string]kubecontainer.RuntimeHandler
usernsEnabled bool
expected *runtimeapi.NamespaceOption
expErr bool
}{
"nil pod -> default v1 namespaces": {
input: nil,
@ -221,11 +239,84 @@ func TestNamespacesForPod(t *testing.T) {
Pid: runtimeapi.NamespaceMode_CONTAINER,
},
},
"hostUsers: false and feature enabled": {
input: &v1.Pod{
Spec: v1.PodSpec{
HostUsers: &[]bool{false}[0],
},
},
usernsEnabled: true,
runtimeHandlers: map[string]kubecontainer.RuntimeHandler{
"": {
SupportsUserNamespaces: true,
},
},
expected: &runtimeapi.NamespaceOption{
Ipc: runtimeapi.NamespaceMode_POD,
Network: runtimeapi.NamespaceMode_POD,
Pid: runtimeapi.NamespaceMode_CONTAINER,
UsernsOptions: &runtimeapi.UserNamespace{
Mode: runtimeapi.NamespaceMode_POD,
Uids: []*runtimeapi.IDMapping{usernsIDs},
Gids: []*runtimeapi.IDMapping{usernsIDs},
},
},
},
// The hostUsers field can't be set to any value if the feature is disabled.
"hostUsers: false and feature disabled --> error": {
input: &v1.Pod{
Spec: v1.PodSpec{
HostUsers: &[]bool{false}[0],
},
},
usernsEnabled: false,
expErr: true,
},
// The hostUsers field can't be set to any value if the feature is disabled.
"hostUsers: true and feature disabled --> error": {
input: &v1.Pod{
Spec: v1.PodSpec{
HostUsers: &[]bool{true}[0],
},
},
usernsEnabled: false,
expErr: true,
},
"error if runtime handler not found": {
input: &v1.Pod{
Spec: v1.PodSpec{
HostUsers: &[]bool{false}[0],
},
},
usernsEnabled: true,
runtimeHandlers: map[string]kubecontainer.RuntimeHandler{
"other": {},
},
expErr: true,
},
"error if runtime handler does not support userns": {
input: &v1.Pod{
Spec: v1.PodSpec{
HostUsers: &[]bool{false}[0],
},
},
usernsEnabled: true,
expErr: true,
},
} {
t.Run(desc, func(t *testing.T) {
actual, err := NamespacesForPod(test.input, &kubecontainertest.FakeRuntimeHelper{}, nil)
require.NoError(t, err)
require.Equal(t, test.expected, actual)
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.UserNamespacesSupport, test.usernsEnabled)
fakeRuntimeHelper := kubecontainertest.FakeRuntimeHelper{
RuntimeHandlers: test.runtimeHandlers,
}
actual, err := NamespacesForPod(test.input, &fakeRuntimeHelper, &fakeRuntimeHandlerResolver{})
if test.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, test.expected, actual)
}
})
}
}