Add ImageVolumeSource implementation

This patch adds the kubelet implementation of the image volume source
feature.

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
This commit is contained in:
Sascha Grunert
2024-06-24 11:31:06 +02:00
parent c4bd05df1c
commit 979863d15c
20 changed files with 563 additions and 76 deletions

View File

@@ -18,6 +18,7 @@ package kuberuntime
import (
"context"
"errors"
"fmt"
"path/filepath"
"reflect"
@@ -48,6 +49,7 @@ import (
"k8s.io/kubernetes/pkg/features"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
imagetypes "k8s.io/kubernetes/pkg/kubelet/images"
proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
)
@@ -171,7 +173,7 @@ func makeFakeContainer(t *testing.T, m *kubeGenericRuntimeManager, template cont
sandboxConfig, err := m.generatePodSandboxConfig(template.pod, template.sandboxAttempt)
assert.NoError(t, err, "generatePodSandboxConfig for container template %+v", template)
containerConfig, _, err := m.generateContainerConfig(ctx, template.container, template.pod, template.attempt, "", template.container.Image, []string{}, nil)
containerConfig, _, err := m.generateContainerConfig(ctx, template.container, template.pod, template.attempt, "", template.container.Image, []string{}, nil, nil)
assert.NoError(t, err, "generateContainerConfig for container template %+v", template)
podSandboxID := apitest.BuildSandboxName(sandboxConfig.Metadata)
@@ -2578,3 +2580,131 @@ func TestUpdatePodContainerResources(t *testing.T) {
}
}
}
func TestToKubeContainerImageVolumes(t *testing.T) {
_, _, manager, err := createTestRuntimeManager()
require.NoError(t, err)
const (
volume1 = "volume-1"
volume2 = "volume-2"
)
imageSpec1 := runtimeapi.ImageSpec{Image: "image-1"}
imageSpec2 := runtimeapi.ImageSpec{Image: "image-2"}
errTest := errors.New("pull failed")
syncResult := kubecontainer.NewSyncResult(kubecontainer.StartContainer, "test")
for desc, tc := range map[string]struct {
pullResults imageVolumePulls
container *v1.Container
expectedError error
expectedImageVolumes kubecontainer.ImageVolumes
}{
"empty volumes": {},
"multiple volumes": {
pullResults: imageVolumePulls{
volume1: imageVolumePullResult{spec: imageSpec1},
volume2: imageVolumePullResult{spec: imageSpec2},
},
container: &v1.Container{
VolumeMounts: []v1.VolumeMount{
{Name: volume1},
{Name: volume2},
},
},
expectedImageVolumes: kubecontainer.ImageVolumes{
volume1: &imageSpec1,
volume2: &imageSpec2,
},
},
"not matching volume": {
pullResults: imageVolumePulls{
"different": imageVolumePullResult{spec: imageSpec1},
},
container: &v1.Container{
VolumeMounts: []v1.VolumeMount{{Name: volume1}},
},
expectedImageVolumes: kubecontainer.ImageVolumes{},
},
"error in pull result": {
pullResults: imageVolumePulls{
volume1: imageVolumePullResult{err: errTest},
},
container: &v1.Container{
VolumeMounts: []v1.VolumeMount{
{Name: volume1},
},
},
expectedError: errTest,
},
} {
imageVolumes, err := manager.toKubeContainerImageVolumes(tc.pullResults, tc.container, &v1.Pod{}, syncResult)
if tc.expectedError != nil {
require.EqualError(t, err, tc.expectedError.Error())
} else {
require.NoError(t, err, desc)
}
assert.Equal(t, tc.expectedImageVolumes, imageVolumes)
}
}
func TestGetImageVolumes(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ImageVolume, true)
_, _, manager, err := createTestRuntimeManager()
require.NoError(t, err)
const (
volume1 = "volume-1"
volume2 = "volume-2"
image1 = "image-1:latest"
image2 = "image-2:latest"
)
imageSpec1 := runtimeapi.ImageSpec{Image: image1, UserSpecifiedImage: image1}
imageSpec2 := runtimeapi.ImageSpec{Image: image2, UserSpecifiedImage: image2}
for desc, tc := range map[string]struct {
pod *v1.Pod
expectedImageVolumePulls imageVolumePulls
expectedError error
}{
"empty volumes": {
pod: &v1.Pod{Spec: v1.PodSpec{Volumes: []v1.Volume{}}},
expectedImageVolumePulls: imageVolumePulls{},
},
"multiple volumes": {
pod: &v1.Pod{Spec: v1.PodSpec{Volumes: []v1.Volume{
{Name: volume1, VolumeSource: v1.VolumeSource{Image: &v1.ImageVolumeSource{Reference: image1, PullPolicy: v1.PullAlways}}},
{Name: volume2, VolumeSource: v1.VolumeSource{Image: &v1.ImageVolumeSource{Reference: image2, PullPolicy: v1.PullAlways}}},
}}},
expectedImageVolumePulls: imageVolumePulls{
volume1: imageVolumePullResult{spec: imageSpec1},
volume2: imageVolumePullResult{spec: imageSpec2},
},
},
"different than image volumes": {
pod: &v1.Pod{Spec: v1.PodSpec{Volumes: []v1.Volume{
{Name: volume1, VolumeSource: v1.VolumeSource{HostPath: &v1.HostPathVolumeSource{}}},
}}},
expectedImageVolumePulls: imageVolumePulls{},
},
"multiple volumes but one failed to pull": {
pod: &v1.Pod{Spec: v1.PodSpec{Volumes: []v1.Volume{
{Name: volume1, VolumeSource: v1.VolumeSource{Image: &v1.ImageVolumeSource{Reference: image1, PullPolicy: v1.PullAlways}}},
{Name: volume2, VolumeSource: v1.VolumeSource{Image: &v1.ImageVolumeSource{Reference: "image", PullPolicy: v1.PullNever}}}, // fails
}}},
expectedImageVolumePulls: imageVolumePulls{
volume1: imageVolumePullResult{spec: imageSpec1},
volume2: imageVolumePullResult{err: imagetypes.ErrImageNeverPull, msg: `Container image "image" is not present with pull policy of Never`},
},
},
} {
imageVolumePulls, err := manager.getImageVolumes(context.TODO(), tc.pod, nil, nil)
if tc.expectedError != nil {
require.EqualError(t, err, tc.expectedError.Error())
} else {
require.NoError(t, err, desc)
}
assert.Equal(t, tc.expectedImageVolumePulls, imageVolumePulls)
}
}