mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-21 09:34:40 +00:00
TestMakeMounts: add new cases for the image volume feature
This commit is contained in:
parent
bc79d3ba87
commit
2529d7d5a6
@ -20,16 +20,21 @@ limitations under the License.
|
||||
package kubelet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
volumetest "k8s.io/kubernetes/pkg/volume/testing"
|
||||
"k8s.io/kubernetes/pkg/volume/util/hostutil"
|
||||
"k8s.io/kubernetes/pkg/volume/util/subpath"
|
||||
@ -40,16 +45,21 @@ func TestMakeMounts(t *testing.T) {
|
||||
propagationHostToContainer := v1.MountPropagationHostToContainer
|
||||
propagationBidirectional := v1.MountPropagationBidirectional
|
||||
propagationNone := v1.MountPropagationNone
|
||||
image1 := &runtimeapi.ImageSpec{Image: "image1"}
|
||||
image2 := &runtimeapi.ImageSpec{Image: "image2"}
|
||||
|
||||
testCases := map[string]struct {
|
||||
container v1.Container
|
||||
podVolumes kubecontainer.VolumeMap
|
||||
imageVolumes kubecontainer.ImageVolumes
|
||||
imageVolumeFeatureEnabled []bool
|
||||
supportsRRO bool
|
||||
expectErr bool
|
||||
expectedErrMsg string
|
||||
expectedMounts []kubecontainer.Mount
|
||||
}{
|
||||
"valid mounts in unprivileged container": {
|
||||
"valid mounts in unprivileged container": { // TODO: remove it once image volume feature is GA
|
||||
imageVolumeFeatureEnabled: []bool{true, false},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
|
||||
@ -118,7 +128,8 @@ func TestMakeMounts(t *testing.T) {
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"valid mounts in privileged container": {
|
||||
"valid mounts in privileged container": { // TODO: remove it once image volume feature is GA
|
||||
imageVolumeFeatureEnabled: []bool{true, false},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
|
||||
@ -177,7 +188,198 @@ func TestMakeMounts(t *testing.T) {
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"valid mounts in unprivileged container with image volumes": {
|
||||
imageVolumeFeatureEnabled: []bool{true},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
|
||||
"disk5": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/var/lib/kubelet/podID/volumes/empty/disk5"}},
|
||||
"image1": kubecontainer.VolumeInfo{Mounter: &stubVolume{attributes: volume.Attributes{ReadOnly: true}}},
|
||||
"image2": kubecontainer.VolumeInfo{Mounter: &stubVolume{attributes: volume.Attributes{ReadOnly: true}}},
|
||||
},
|
||||
imageVolumes: kubecontainer.ImageVolumes{
|
||||
"image1": image1,
|
||||
"image2": image2,
|
||||
},
|
||||
container: v1.Container{
|
||||
Name: "container1",
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/etc/hosts",
|
||||
Name: "disk",
|
||||
ReadOnly: false,
|
||||
MountPropagation: &propagationHostToContainer,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path3",
|
||||
Name: "disk",
|
||||
ReadOnly: true,
|
||||
MountPropagation: &propagationNone,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path4",
|
||||
Name: "disk4",
|
||||
ReadOnly: false,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path5",
|
||||
Name: "disk5",
|
||||
ReadOnly: false,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/image1",
|
||||
Name: "image1",
|
||||
ReadOnly: false,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/image2",
|
||||
Name: "image2",
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedMounts: []kubecontainer.Mount{
|
||||
{
|
||||
Name: "disk",
|
||||
ContainerPath: "/etc/hosts",
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
{
|
||||
Name: "disk",
|
||||
ContainerPath: "/mnt/path3",
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE,
|
||||
},
|
||||
{
|
||||
Name: "disk4",
|
||||
ContainerPath: "/mnt/path4",
|
||||
HostPath: "/mnt/host",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE,
|
||||
},
|
||||
{
|
||||
Name: "disk5",
|
||||
ContainerPath: "/mnt/path5",
|
||||
HostPath: "/var/lib/kubelet/podID/volumes/empty/disk5",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE,
|
||||
},
|
||||
{
|
||||
Name: "image1",
|
||||
ContainerPath: "/mnt/image1",
|
||||
Image: image1,
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
},
|
||||
{
|
||||
Name: "image2",
|
||||
ContainerPath: "/mnt/image2",
|
||||
Image: image2,
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"valid mounts in privileged container with image volumes": {
|
||||
imageVolumeFeatureEnabled: []bool{true},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
|
||||
"disk5": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/var/lib/kubelet/podID/volumes/empty/disk5"}},
|
||||
"image1": kubecontainer.VolumeInfo{Mounter: &stubVolume{attributes: volume.Attributes{ReadOnly: true}}},
|
||||
"image2": kubecontainer.VolumeInfo{Mounter: &stubVolume{attributes: volume.Attributes{ReadOnly: true}}},
|
||||
},
|
||||
imageVolumes: kubecontainer.ImageVolumes{
|
||||
"image1": image1,
|
||||
"image2": image2,
|
||||
},
|
||||
container: v1.Container{
|
||||
Name: "container1",
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/etc/hosts",
|
||||
Name: "disk",
|
||||
ReadOnly: false,
|
||||
MountPropagation: &propagationBidirectional,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path3",
|
||||
Name: "disk",
|
||||
ReadOnly: true,
|
||||
MountPropagation: &propagationHostToContainer,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path4",
|
||||
Name: "disk4",
|
||||
ReadOnly: false,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/image1",
|
||||
Name: "image1",
|
||||
ReadOnly: false,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/image2",
|
||||
Name: "image2",
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
Privileged: &bTrue,
|
||||
},
|
||||
},
|
||||
expectedMounts: []kubecontainer.Mount{
|
||||
{
|
||||
Name: "disk",
|
||||
ContainerPath: "/etc/hosts",
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL,
|
||||
},
|
||||
{
|
||||
Name: "disk",
|
||||
ContainerPath: "/mnt/path3",
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
{
|
||||
Name: "disk4",
|
||||
ContainerPath: "/mnt/path4",
|
||||
HostPath: "/mnt/host",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE,
|
||||
},
|
||||
{
|
||||
Name: "image1",
|
||||
ContainerPath: "/mnt/image1",
|
||||
Image: image1,
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
},
|
||||
{
|
||||
Name: "image2",
|
||||
ContainerPath: "/mnt/image2",
|
||||
Image: image2,
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"invalid absolute SubPath": {
|
||||
imageVolumeFeatureEnabled: []bool{true, false},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
},
|
||||
@ -195,6 +397,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
expectedErrMsg: "error SubPath `/must/not/be/absolute` must not be an absolute path",
|
||||
},
|
||||
"invalid SubPath with backsteps": {
|
||||
imageVolumeFeatureEnabled: []bool{true, false},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
},
|
||||
@ -212,7 +415,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
expectedErrMsg: "unable to provision SubPath `no/backsteps/../allowed`: must not contain '..'",
|
||||
},
|
||||
"volume doesn't exist": {
|
||||
podVolumes: kubecontainer.VolumeMap{},
|
||||
imageVolumeFeatureEnabled: []bool{true, false},
|
||||
container: v1.Container{
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -226,6 +429,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
expectedErrMsg: "cannot find volume \"disk\" to mount into container \"\"",
|
||||
},
|
||||
"volume mounter is nil": {
|
||||
imageVolumeFeatureEnabled: []bool{true, false},
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{},
|
||||
},
|
||||
@ -244,7 +448,10 @@ func TestMakeMounts(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
for _, featureEnabled := range tc.imageVolumeFeatureEnabled {
|
||||
name := fmt.Sprintf("features.ImageVolume is %v, %s", featureEnabled, name)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ImageVolume, featureEnabled)
|
||||
fhu := hostutil.NewFakeHostUtil(nil)
|
||||
fsp := &subpath.FakeSubpath{}
|
||||
pod := v1.Pod{
|
||||
@ -253,7 +460,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
mounts, _, err := makeMounts(&pod, "/pod", &tc.container, "fakepodname", "", []string{""}, tc.podVolumes, fhu, fsp, nil, tc.supportsRRO, nil)
|
||||
mounts, _, err := makeMounts(&pod, "/pod", &tc.container, "fakepodname", "", []string{""}, tc.podVolumes, fhu, fsp, nil, tc.supportsRRO, tc.imageVolumes)
|
||||
|
||||
// validate only the error if we expect an error
|
||||
if tc.expectErr {
|
||||
@ -271,6 +478,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedMounts, mounts, "mounts of container %+v", tc.container)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeMountsEtcHostsFile(t *testing.T) {
|
||||
|
@ -690,6 +690,7 @@ func TestVolumeUnmountAndDetachControllerEnabled(t *testing.T) {
|
||||
|
||||
type stubVolume struct {
|
||||
path string
|
||||
attributes volume.Attributes
|
||||
volume.MetricsNil
|
||||
}
|
||||
|
||||
@ -698,7 +699,7 @@ func (f *stubVolume) GetPath() string {
|
||||
}
|
||||
|
||||
func (f *stubVolume) GetAttributes() volume.Attributes {
|
||||
return volume.Attributes{}
|
||||
return f.attributes
|
||||
}
|
||||
|
||||
func (f *stubVolume) SetUp(mounterArgs volume.MounterArgs) error {
|
||||
|
Loading…
Reference in New Issue
Block a user