mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
Add unit tests for DesiredStateOfWorldPopulator
This commit is contained in:
parent
39f0d78714
commit
f9c7ce5b9c
@ -31,7 +31,9 @@ import (
|
|||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
csitrans "k8s.io/csi-translation-lib"
|
csitrans "k8s.io/csi-translation-lib"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/configmap"
|
"k8s.io/kubernetes/pkg/kubelet/configmap"
|
||||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||||
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
|
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
|
||||||
@ -1067,6 +1069,195 @@ func TestCheckVolumeFSResize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckVolumeSELinux(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
|
||||||
|
fullOpts := &v1.SELinuxOptions{
|
||||||
|
User: "system_u",
|
||||||
|
Role: "object_r",
|
||||||
|
Type: "container_t",
|
||||||
|
Level: "s0:c1,c2",
|
||||||
|
}
|
||||||
|
differentFullOpts := &v1.SELinuxOptions{
|
||||||
|
User: "system_u",
|
||||||
|
Role: "object_r",
|
||||||
|
Type: "container_t",
|
||||||
|
Level: "s0:c9998,c9999",
|
||||||
|
}
|
||||||
|
partialOpts := &v1.SELinuxOptions{
|
||||||
|
Level: "s0:c3,c4",
|
||||||
|
}
|
||||||
|
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
accessModes []v1.PersistentVolumeAccessMode
|
||||||
|
existingContainerSELinuxOpts *v1.SELinuxOptions
|
||||||
|
newContainerSELinuxOpts *v1.SELinuxOptions
|
||||||
|
pluginSupportsSELinux bool
|
||||||
|
expectError bool
|
||||||
|
expectedContext string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "RWOP with plugin with SELinux with full context in pod",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod},
|
||||||
|
newContainerSELinuxOpts: fullOpts,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectedContext: "system_u:object_r:container_file_t:s0:c1,c2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "RWOP with plugin with SELinux with partial context in pod",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod},
|
||||||
|
newContainerSELinuxOpts: partialOpts,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectedContext: "system_u:object_r:container_file_t:s0:c3,c4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "RWX with plugin with SELinux with fill context in pod",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany},
|
||||||
|
newContainerSELinuxOpts: fullOpts,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectedContext: "", // RWX volumes don't support SELinux
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "RWOP with plugin with no SELinux with fill context in pod",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod},
|
||||||
|
newContainerSELinuxOpts: fullOpts,
|
||||||
|
pluginSupportsSELinux: false,
|
||||||
|
expectedContext: "", // plugin doesn't support SELinux
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "RWOP with plugin with SELinux with no context in pod",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod},
|
||||||
|
newContainerSELinuxOpts: nil,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectedContext: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "RWOP with plugin with SELinux with full context in pod with existing pod",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod},
|
||||||
|
existingContainerSELinuxOpts: fullOpts,
|
||||||
|
newContainerSELinuxOpts: fullOpts,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectedContext: "system_u:object_r:container_file_t:s0:c1,c2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mismatched SELinux with RWX - success",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany},
|
||||||
|
existingContainerSELinuxOpts: fullOpts,
|
||||||
|
newContainerSELinuxOpts: differentFullOpts,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectedContext: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mismatched SELinux with RWOP - failure",
|
||||||
|
accessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod},
|
||||||
|
existingContainerSELinuxOpts: fullOpts,
|
||||||
|
newContainerSELinuxOpts: differentFullOpts,
|
||||||
|
pluginSupportsSELinux: true,
|
||||||
|
expectError: true,
|
||||||
|
// The original seLinuxOpts are kept in DSW
|
||||||
|
expectedContext: "system_u:object_r:container_file_t:s0:c1,c2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testcases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
pv := &v1.PersistentVolume{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "dswp-test-volume-name",
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: v1.PersistentVolumeSource{RBD: &v1.RBDPersistentVolumeSource{}},
|
||||||
|
Capacity: volumeCapacity(1),
|
||||||
|
ClaimRef: &v1.ObjectReference{Namespace: "ns", Name: "file-bound"},
|
||||||
|
AccessModes: tc.accessModes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pvc := &v1.PersistentVolumeClaim{
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: pv.Name,
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: pv.Spec.Capacity,
|
||||||
|
},
|
||||||
|
AccessModes: tc.accessModes,
|
||||||
|
},
|
||||||
|
Status: v1.PersistentVolumeClaimStatus{
|
||||||
|
Phase: v1.ClaimBound,
|
||||||
|
Capacity: pv.Spec.Capacity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
container := v1.Container{
|
||||||
|
SecurityContext: &v1.SecurityContext{
|
||||||
|
SELinuxOptions: nil,
|
||||||
|
},
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: pv.Name,
|
||||||
|
MountPath: "/mnt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeVolumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
|
||||||
|
plugin.SupportsSELinux = tc.pluginSupportsSELinux
|
||||||
|
dswp, fakePodManager, fakeDSW, _, _ := createDswpWithVolumeWithCustomPluginMgr(t, pv, pvc, fakeVolumePluginMgr)
|
||||||
|
|
||||||
|
var existingPod *v1.Pod
|
||||||
|
if tc.existingContainerSELinuxOpts != nil {
|
||||||
|
// Add existing pod + volume
|
||||||
|
existingContainer := container
|
||||||
|
existingContainer.SecurityContext.SELinuxOptions = tc.existingContainerSELinuxOpts
|
||||||
|
existingPod = createPodWithVolume("dswp-old-pod", "dswp-test-volume-name", "file-bound", []v1.Container{existingContainer})
|
||||||
|
fakePodManager.AddPod(existingPod)
|
||||||
|
dswp.findAndAddNewPods()
|
||||||
|
}
|
||||||
|
|
||||||
|
newContainer := container
|
||||||
|
newContainer.SecurityContext.SELinuxOptions = tc.newContainerSELinuxOpts
|
||||||
|
newPod := createPodWithVolume("dswp-test-pod", "dswp-test-volume-name", "file-bound", []v1.Container{newContainer})
|
||||||
|
|
||||||
|
// Act - add the new Pod
|
||||||
|
fakePodManager.AddPod(newPod)
|
||||||
|
dswp.findAndAddNewPods()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
|
||||||
|
// Check the global volume state
|
||||||
|
uniquePodName := types.UniquePodName(newPod.UID)
|
||||||
|
uniqueVolumeName := v1.UniqueVolumeName("fake-plugin/" + newPod.Spec.Volumes[0].Name)
|
||||||
|
volumeExists := fakeDSW.VolumeExists(uniqueVolumeName, tc.expectedContext)
|
||||||
|
if !volumeExists {
|
||||||
|
t.Errorf(
|
||||||
|
"VolumeExists(%q) failed. Expected: <true> Actual: <%v>",
|
||||||
|
uniqueVolumeName,
|
||||||
|
volumeExists)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the Pod local volume state
|
||||||
|
podExistsInVolume := fakeDSW.PodExistsInVolume(uniquePodName, uniqueVolumeName, tc.expectedContext)
|
||||||
|
if !podExistsInVolume && !tc.expectError {
|
||||||
|
t.Errorf(
|
||||||
|
"DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>",
|
||||||
|
podExistsInVolume)
|
||||||
|
}
|
||||||
|
if podExistsInVolume && tc.expectError {
|
||||||
|
t.Errorf(
|
||||||
|
"DSW PodExistsInVolume returned incorrect value. Expected: <false> Actual: <%v>",
|
||||||
|
podExistsInVolume)
|
||||||
|
}
|
||||||
|
errors := fakeDSW.GetPodsWithErrors()
|
||||||
|
if tc.expectError && len(errors) == 0 {
|
||||||
|
t.Errorf("Expected Pod error, got none")
|
||||||
|
}
|
||||||
|
if !tc.expectError && len(errors) > 0 {
|
||||||
|
t.Errorf("Unexpected Pod errors: %v", errors)
|
||||||
|
}
|
||||||
|
verifyVolumeExistsInVolumesToMount(t, uniqueVolumeName, false /* expectReportedInUse */, fakeDSW)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createResizeRelatedVolumes(volumeMode *v1.PersistentVolumeMode) (pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
|
func createResizeRelatedVolumes(volumeMode *v1.PersistentVolumeMode) (pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
|
||||||
pv = &v1.PersistentVolume{
|
pv = &v1.PersistentVolume{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -1175,7 +1366,7 @@ func createPodWithVolume(pod, pv, pvc string, containers []v1.Container) *v1.Pod
|
|||||||
return &v1.Pod{
|
return &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: pod,
|
Name: pod,
|
||||||
UID: "dswp-test-pod-uid",
|
UID: kubetypes.UID(pod + "-uid"),
|
||||||
Namespace: "dswp-test",
|
Namespace: "dswp-test",
|
||||||
},
|
},
|
||||||
Spec: v1.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
|
@ -28,7 +28,10 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/util/slice"
|
"k8s.io/kubernetes/pkg/util/slice"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
utilptr "k8s.io/utils/pointer"
|
utilptr "k8s.io/utils/pointer"
|
||||||
|
Loading…
Reference in New Issue
Block a user