Skip to content

Commit

Permalink
Add unit tests for DesiredStateOfWorldPopulator
Browse files Browse the repository at this point in the history
  • Loading branch information
jsafrane committed Aug 4, 2022
1 parent 39f0d78 commit f9c7ce5
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
featuregatetesting "k8s.io/component-base/featuregate/testing"
csitrans "k8s.io/csi-translation-lib"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/configmap"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
Expand Down Expand Up @@ -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) {
pv = &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -1175,7 +1366,7 @@ func createPodWithVolume(pod, pv, pvc string, containers []v1.Container) *v1.Pod
return &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: pod,
UID: "dswp-test-pod-uid",
UID: kubetypes.UID(pod + "-uid"),
Namespace: "dswp-test",
},
Spec: v1.PodSpec{
Expand Down
3 changes: 3 additions & 0 deletions pkg/volume/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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/features"
"k8s.io/kubernetes/pkg/util/slice"
"k8s.io/kubernetes/pkg/volume"
utilptr "k8s.io/utils/pointer"
Expand Down

0 comments on commit f9c7ce5

Please sign in to comment.