mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
[kubelet][podadmission]: Validate and reject pods with mismatching labels
This commit is contained in:
parent
02c1bac0b6
commit
21c5c2ec5c
@ -18,6 +18,7 @@ package lifecycle
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apiserver/pkg/util/feature"
|
"k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -153,11 +154,39 @@ func (w *predicateAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult
|
|||||||
Message: message,
|
Message: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if rejectPodAdmissionBasedOnOSSelector(admitPod, node) {
|
||||||
|
return PodAdmitResult{
|
||||||
|
Admit: false,
|
||||||
|
Reason: "PodOSSelectorNodeLabelDoesNotMatch",
|
||||||
|
Message: "Failed to admit pod as the `kubernetes.io/os` label doesn't match node label",
|
||||||
|
}
|
||||||
|
}
|
||||||
return PodAdmitResult{
|
return PodAdmitResult{
|
||||||
Admit: true,
|
Admit: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rejectPodAdmissionBasedOnOSSelector rejects pod if it's nodeSelector doesn't match
|
||||||
|
// We expect the kubelet status reconcile which happens every 10sec to update the node labels if there is a mismatch.
|
||||||
|
func rejectPodAdmissionBasedOnOSSelector(pod *v1.Pod, node *v1.Node) bool {
|
||||||
|
labels := node.Labels
|
||||||
|
osName, osLabelExists := labels[v1.LabelOSStable]
|
||||||
|
if !osLabelExists || osName != runtime.GOOS {
|
||||||
|
if len(labels) == 0 {
|
||||||
|
labels = make(map[string]string)
|
||||||
|
}
|
||||||
|
labels[v1.LabelOSStable] = runtime.GOOS
|
||||||
|
}
|
||||||
|
podLabelSelector, podOSLabelExists := pod.Labels[v1.LabelOSStable]
|
||||||
|
if !podOSLabelExists {
|
||||||
|
// If the labelselector didn't exist, let's keep the current behavior as is
|
||||||
|
return false
|
||||||
|
} else if podOSLabelExists && podLabelSelector != labels[v1.LabelOSStable] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func removeMissingExtendedResources(pod *v1.Pod, nodeInfo *schedulerframework.NodeInfo) *v1.Pod {
|
func removeMissingExtendedResources(pod *v1.Pod, nodeInfo *schedulerframework.NodeInfo) *v1.Pod {
|
||||||
podCopy := pod.DeepCopy()
|
podCopy := pod.DeepCopy()
|
||||||
for i, c := range pod.Spec.Containers {
|
for i, c := range pod.Spec.Containers {
|
||||||
|
@ -18,6 +18,7 @@ package lifecycle
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
goruntime "runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
@ -267,3 +268,57 @@ func TestGeneralPredicates(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRejectPodAdmissionBasedOnOSSelector(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
pod *v1.Pod
|
||||||
|
node *v1.Node
|
||||||
|
expectRejection bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OS label match",
|
||||||
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: goruntime.GOOS}}},
|
||||||
|
node: &v1.Node{Spec: v1.NodeSpec{}, ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: goruntime.GOOS}}},
|
||||||
|
expectRejection: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dummyOS label, but the underlying OS matches",
|
||||||
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: goruntime.GOOS}}},
|
||||||
|
node: &v1.Node{Spec: v1.NodeSpec{}, ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
expectRejection: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dummyOS label, but the underlying OS doesn't match",
|
||||||
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
node: &v1.Node{Spec: v1.NodeSpec{}, ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
expectRejection: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dummyOS label, but the underlying OS doesn't match",
|
||||||
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
node: &v1.Node{Spec: v1.NodeSpec{}, ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
expectRejection: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OS field mismatch, OS label on node object would be reset to correct value",
|
||||||
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
node: &v1.Node{Spec: v1.NodeSpec{}, ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
expectRejection: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "No label selector on the pod, should be admitted",
|
||||||
|
pod: &v1.Pod{},
|
||||||
|
node: &v1.Node{Spec: v1.NodeSpec{}, ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{v1.LabelOSStable: "dummyOS"}}},
|
||||||
|
expectRejection: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
actualResult := rejectPodAdmissionBasedOnOSSelector(test.pod, test.node)
|
||||||
|
if test.expectRejection != actualResult {
|
||||||
|
t.Errorf("unexpected result, expected %v but got %v", test.expectRejection, actualResult)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user