mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-13 05:46:16 +00:00
Merge pull request #103133 from marwanad/allow-scheduler-to-patch-conditions
switch scheduler to generate the merge patch on pod status instead of the full pod
This commit is contained in:
commit
51e1969d9c
@ -413,17 +413,17 @@ func truncateMessage(message string) string {
|
|||||||
|
|
||||||
func updatePod(client clientset.Interface, pod *v1.Pod, condition *v1.PodCondition, nominatedNode string) error {
|
func updatePod(client clientset.Interface, pod *v1.Pod, condition *v1.PodCondition, nominatedNode string) error {
|
||||||
klog.V(3).InfoS("Updating pod condition", "pod", klog.KObj(pod), "conditionType", condition.Type, "conditionStatus", condition.Status, "conditionReason", condition.Reason)
|
klog.V(3).InfoS("Updating pod condition", "pod", klog.KObj(pod), "conditionType", condition.Type, "conditionStatus", condition.Status, "conditionReason", condition.Reason)
|
||||||
podCopy := pod.DeepCopy()
|
podStatusCopy := pod.Status.DeepCopy()
|
||||||
// NominatedNodeName is updated only if we are trying to set it, and the value is
|
// NominatedNodeName is updated only if we are trying to set it, and the value is
|
||||||
// different from the existing one.
|
// different from the existing one.
|
||||||
if !podutil.UpdatePodCondition(&podCopy.Status, condition) &&
|
if !podutil.UpdatePodCondition(podStatusCopy, condition) &&
|
||||||
(len(nominatedNode) == 0 || pod.Status.NominatedNodeName == nominatedNode) {
|
(len(nominatedNode) == 0 || pod.Status.NominatedNodeName == nominatedNode) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if nominatedNode != "" {
|
if nominatedNode != "" {
|
||||||
podCopy.Status.NominatedNodeName = nominatedNode
|
podStatusCopy.NominatedNodeName = nominatedNode
|
||||||
}
|
}
|
||||||
return util.PatchPod(client, pod, podCopy)
|
return util.PatchPodStatus(client, pod, podStatusCopy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume signals to the cache that a pod is already in the cache, so that binding can be asynchronous.
|
// assume signals to the cache that a pod is already in the cache, so that binding can be asynchronous.
|
||||||
|
@ -90,15 +90,19 @@ func MoreImportantPod(pod1, pod2 *v1.Pod) bool {
|
|||||||
return GetPodStartTime(pod1).Before(GetPodStartTime(pod2))
|
return GetPodStartTime(pod1).Before(GetPodStartTime(pod2))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchPod calculates the delta bytes change from <old> to <new>,
|
// PatchPodStatus calculates the delta bytes change from <old.Status> to <newStatus>,
|
||||||
// and then submit a request to API server to patch the pod changes.
|
// and then submit a request to API server to patch the pod changes.
|
||||||
func PatchPod(cs kubernetes.Interface, old *v1.Pod, new *v1.Pod) error {
|
func PatchPodStatus(cs kubernetes.Interface, old *v1.Pod, newStatus *v1.PodStatus) error {
|
||||||
oldData, err := json.Marshal(old)
|
if newStatus == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
oldData, err := json.Marshal(v1.Pod{Status: old.Status})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newData, err := json.Marshal(new)
|
newData, err := json.Marshal(v1.Pod{Status: *newStatus})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -128,9 +132,9 @@ func ClearNominatedNodeName(cs kubernetes.Interface, pods ...*v1.Pod) utilerrors
|
|||||||
if len(p.Status.NominatedNodeName) == 0 {
|
if len(p.Status.NominatedNodeName) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
podCopy := p.DeepCopy()
|
podStatusCopy := p.Status.DeepCopy()
|
||||||
podCopy.Status.NominatedNodeName = ""
|
podStatusCopy.NominatedNodeName = ""
|
||||||
if err := PatchPod(cs, p, podCopy); err != nil {
|
if err := PatchPodStatus(cs, p, podStatusCopy); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -173,3 +175,80 @@ func TestRemoveNominatedNodeName(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPatchPodStatus(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
pod v1.Pod
|
||||||
|
statusToUpdate v1.PodStatus
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Should update pod conditions successfully",
|
||||||
|
pod: v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "pod1",
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
ImagePullSecrets: []v1.LocalObjectReference{{Name: "foo"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
statusToUpdate: v1.PodStatus{
|
||||||
|
Conditions: []v1.PodCondition{
|
||||||
|
{
|
||||||
|
Type: v1.PodScheduled,
|
||||||
|
Status: v1.ConditionFalse,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ref: #101697, #94626 - ImagePullSecrets are allowed to have empty secret names
|
||||||
|
// which would fail the 2-way merge patch generation on Pod patches
|
||||||
|
// due to the mergeKey being the name field
|
||||||
|
name: "Should update pod conditions successfully on a pod Spec with secrets with empty name",
|
||||||
|
pod: v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "pod2",
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
// this will serialize to imagePullSecrets:[{}]
|
||||||
|
ImagePullSecrets: make([]v1.LocalObjectReference, 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
statusToUpdate: v1.PodStatus{
|
||||||
|
Conditions: []v1.PodCondition{
|
||||||
|
{
|
||||||
|
Type: v1.PodScheduled,
|
||||||
|
Status: v1.ConditionFalse,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
client := clientsetfake.NewSimpleClientset()
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
_, err := client.CoreV1().Pods(tc.pod.Namespace).Create(context.TODO(), &tc.pod, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PatchPodStatus(client, &tc.pod, &tc.statusToUpdate)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retrievedPod, err := client.CoreV1().Pods(tc.pod.Namespace).Get(context.TODO(), tc.pod.Name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(tc.statusToUpdate, retrievedPod.Status); diff != "" {
|
||||||
|
t.Errorf("unexpected pod status (-want,+got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user