Change equivalence hash function.

This changes the equivalence class hashing function to use as inputs all
the Pod fields which are read by FitPredicates. Before we used a
combination of OwnerReference and PersistentVolumeClaim info, which was
a close approximation. The new method ensures that hashing remains
correct regardless of controller behavior.

The PVCSet field can be removed from equivalencePod because it is
implicitly included in the Volume list.

Tests are now broken.
This commit is contained in:
Jonathan Basseri 2018-01-18 15:49:57 -08:00
parent 4ae7075e27
commit 5ab4714520

View File

@ -17,11 +17,8 @@ limitations under the License.
package predicates package predicates
import ( import (
"github.com/golang/glog"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/scheduler/algorithm" "k8s.io/kubernetes/pkg/scheduler/algorithm"
schedutil "k8s.io/kubernetes/pkg/scheduler/util" schedutil "k8s.io/kubernetes/pkg/scheduler/util"
) )
@ -83,53 +80,35 @@ func NewEquivalencePodGenerator(pvcInfo PersistentVolumeClaimInfo) algorithm.Get
return g.getEquivalencePod return g.getEquivalencePod
} }
// GetEquivalencePod returns a EquivalencePod which contains a group of pod attributes which can be reused. // GetEquivalencePod returns a equivalencePod which contains a group of pod attributes which can be reused.
func (e *EquivalencePodGenerator) getEquivalencePod(pod *v1.Pod) interface{} { func (e *EquivalencePodGenerator) getEquivalencePod(pod *v1.Pod) interface{} {
// For now we only consider pods: // For equivalence hash to be formally correct, lists and maps
// 1. OwnerReferences is Controller // in the equivalencePod should be normalized. (e.g. by sorting
// 2. with same OwnerReferences // them) However, the vast majority of equivalent pod classes
// 3. with same PVC claim // are expected to be created from a single pod template, so
// to be equivalent // they will all have the same ordering.
for _, ref := range pod.OwnerReferences { return &equivalencePod{
if ref.Controller != nil && *ref.Controller { Labels: pod.Labels,
if pvcSet, err := e.getPVCSet(pod); err == nil { Affinity: pod.Spec.Affinity,
// A pod can only belongs to one controller, so let's return. Containers: pod.Spec.Containers,
return &EquivalencePod{ InitContainers: pod.Spec.InitContainers,
ControllerRef: ref, NodeName: &pod.Spec.NodeName,
PVCSet: pvcSet, NodeSelector: pod.Spec.NodeSelector,
Tolerations: pod.Spec.Tolerations,
Volumes: pod.Spec.Volumes,
} }
} else {
// If error encountered, log warning and return nil (i.e. no equivalent pod found)
glog.Warningf("[EquivalencePodGenerator] for pod: %v failed due to: %v", pod.GetName(), err)
return nil
}
}
}
return nil
} }
// getPVCSet returns a set of PVC UIDs of given pod. // equivalencePod is a group of pod attributes which can be reused as equivalence to schedule other pods.
func (e *EquivalencePodGenerator) getPVCSet(pod *v1.Pod) (sets.String, error) { type equivalencePod struct {
result := sets.NewString() Labels map[string]string
for _, volume := range pod.Spec.Volumes { Affinity *v1.Affinity
if volume.PersistentVolumeClaim == nil { Containers []v1.Container // note about ordering
continue InitContainers []v1.Container // note about ordering
} NodeName *string
pvcName := volume.PersistentVolumeClaim.ClaimName NodeSelector map[string]string
pvc, err := e.pvcInfo.GetPersistentVolumeClaimInfo(pod.GetNamespace(), pvcName) Tolerations []v1.Toleration
if err != nil { Volumes []v1.Volume // note about ordering
return nil, err
}
result.Insert(string(pvc.UID))
}
return result, nil
}
// EquivalencePod is a group of pod attributes which can be reused as equivalence to schedule other pods.
type EquivalencePod struct {
ControllerRef metav1.OwnerReference
PVCSet sets.String
} }
// portsConflict check whether existingPorts and wantPorts conflict with each other // portsConflict check whether existingPorts and wantPorts conflict with each other