Implementing PR feedback

This commit is contained in:
Abhishek Gupta
2015-01-05 14:51:22 -08:00
parent 3f722a3d8e
commit 9e75a05df0
10 changed files with 86 additions and 98 deletions

View File

@@ -59,8 +59,8 @@ func (f FakePodLister) List(s labels.Selector) (selected []api.Pod, err error) {
type ServiceLister interface {
// Lists all the services
ListServices() (api.ServiceList, error)
// Gets the service for the given pod
GetPodService(api.Pod) (api.Service, error)
// Gets the services for the given pod
GetPodServices(api.Pod) ([]api.Service, error)
}
// FakeServiceLister implements ServiceLister on []api.Service for test purposes.
@@ -71,10 +71,8 @@ func (f FakeServiceLister) ListServices() (api.ServiceList, error) {
return api.ServiceList{Items: f}, nil
}
// GetPodService gets the service that has the selector that can match the labels on the given pod
// We are assuming a single service per pod.
// In case of multiple services per pod, the first service found is returned
func (f FakeServiceLister) GetPodService(pod api.Pod) (service api.Service, err error) {
// GetPodServices gets the services that have the selector that match the labels on the given pod
func (f FakeServiceLister) GetPodServices(pod api.Pod) (services []api.Service, err error) {
var selector labels.Selector
for _, service := range f {
@@ -84,8 +82,12 @@ func (f FakeServiceLister) GetPodService(pod api.Pod) (service api.Service, err
}
selector = labels.Set(service.Spec.Selector).AsSelector()
if selector.Matches(labels.Set(pod.Labels)) {
return service, nil
services = append(services, service)
}
}
return service, fmt.Errorf("Could not find service for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels)
if len(services) == 0 {
err = fmt.Errorf("Could not find service for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels)
}
return
}

View File

@@ -182,7 +182,12 @@ func NewNodeLabelPredicate(info NodeInfo, labels []string, presence bool) FitPre
return labelChecker.CheckNodeLabelPresence
}
// CheckNodeLabelPresence checks whether a particular label exists on a minion or not, regardless of its value
// CheckNodeLabelPresence checks whether all of the specified labels exists on a minion or not, regardless of their value
// If "presence" is false, then returns false if any of the requested labels matches any of the minion's labels,
// otherwise returns true.
// If "presence" is true, then returns false if any of the requested labels does not match any of the minion's labels,
// otherwise returns true.
//
// Consider the cases where the minions are placed in regions/zones/racks and these are identified by labels
// In some cases, it is required that only minions that are part of ANY of the defined regions/zones/racks be selected
//
@@ -195,8 +200,9 @@ func (n *NodeLabelChecker) CheckNodeLabelPresence(pod api.Pod, existingPods []ap
if err != nil {
return false, err
}
minionLabels := labels.Set(minion.Labels)
for _, label := range n.labels {
exists = labels.Set(minion.Labels).Has(label)
exists = minionLabels.Has(label)
if (exists && !n.presence) || (!exists && n.presence) {
return false, nil
}
@@ -221,15 +227,20 @@ func NewServiceAffinityPredicate(podLister PodLister, serviceLister ServiceListe
return affinity.CheckServiceAffinity
}
// CheckServiceAffinity ensures that only the minions that match the specified labels are considered for scheduling.
// The set of labels to be considered are provided to the struct (ServiceAffinity).
// The pod is checked for the labels and any missing labels are then checked in the minion
// that hosts the service pods (peers) for the given pod.
func (s *ServiceAffinity) CheckServiceAffinity(pod api.Pod, existingPods []api.Pod, node string) (bool, error) {
var affinitySelector labels.Selector
// check if the pod being scheduled has the affinity labels specified
// check if the pod being scheduled has the affinity labels specified in its NodeSelector
affinityLabels := map[string]string{}
nodeSelector := labels.Set(pod.Spec.NodeSelector)
labelsExist := true
for _, l := range s.labels {
if labels.Set(pod.Labels).Has(l) {
affinityLabels[l] = labels.Set(pod.Labels).Get(l)
if nodeSelector.Has(l) {
affinityLabels[l] = nodeSelector.Get(l)
} else {
// the current pod does not specify all the labels, look in the existing service pods
labelsExist = false
@@ -238,9 +249,11 @@ func (s *ServiceAffinity) CheckServiceAffinity(pod api.Pod, existingPods []api.P
// skip looking at other pods in the service if the current pod defines all the required affinity labels
if !labelsExist {
service, err := s.serviceLister.GetPodService(pod)
services, err := s.serviceLister.GetPodServices(pod)
if err == nil {
selector := labels.SelectorFromSet(service.Spec.Selector)
// just use the first service and get the other pods within the service
// TODO: a separate predicate can be created that tries to handle all services for the pod
selector := labels.SelectorFromSet(services[0].Spec.Selector)
servicePods, err := s.podLister.ListPods(selector)
if err != nil {
return false, err

View File

@@ -502,14 +502,14 @@ func TestServiceAffinity(t *testing.T) {
test: "nothing scheduled",
},
{
pod: api.Pod{ObjectMeta: api.ObjectMeta{Labels: map[string]string{"region": "r1"}}},
pod: api.Pod{Spec: api.PodSpec{NodeSelector: map[string]string{"region": "r1"}}},
node: "machine1",
fits: true,
labels: []string{"region"},
test: "pod with region label match",
},
{
pod: api.Pod{ObjectMeta: api.ObjectMeta{Labels: map[string]string{"region": "r2"}}},
pod: api.Pod{Spec: api.PodSpec{NodeSelector: map[string]string{"region": "r2"}}},
node: "machine1",
fits: false,
labels: []string{"region"},

View File

@@ -103,9 +103,9 @@ func NewNodeLabelPriority(label string, presence bool) PriorityFunction {
return labelPrioritizer.CalculateNodeLabelPriority
}
// CalculateNodeLabelPriority checks whether a particular label exists on a minion or not, regardless of its value
// Consider the cases where the minions are places in regions/zones/racks and these are identified by labels
// In some cases, it is required that only minions that are part of ANY of the defined regions/zones/racks be selected
// CalculateNodeLabelPriority checks whether a particular label exists on a minion or not, regardless of its value.
// If presence is true, prioritizes minions that have the specified label, regardless of value.
// If presence is false, prioritizes minions that do not have the specified label.
func (n *NodeLabelPrioritizer) CalculateNodeLabelPriority(pod api.Pod, podLister PodLister, minionLister MinionLister) (HostPriorityList, error) {
var score int
minions, err := minionLister.List()
@@ -113,7 +113,6 @@ func (n *NodeLabelPrioritizer) CalculateNodeLabelPriority(pod api.Pod, podLister
return nil, err
}
// find the zones that the minions belong to
labeledMinions := map[string]bool{}
for _, minion := range minions.Items {
exists := labels.Set(minion.Labels).Has(n.label)

View File

@@ -41,9 +41,11 @@ func (s *ServiceSpread) CalculateSpreadPriority(pod api.Pod, podLister PodLister
var pods []api.Pod
var err error
service, err := s.serviceLister.GetPodService(pod)
services, err := s.serviceLister.GetPodServices(pod)
if err == nil {
selector := labels.SelectorFromSet(service.Spec.Selector)
// just use the first service and get the other pods within the service
// TODO: a separate predicate can be created that tries to handle all services for the pod
selector := labels.SelectorFromSet(services[0].Spec.Selector)
pods, err = podLister.ListPods(selector)
if err != nil {
return nil, err
@@ -94,13 +96,13 @@ func NewServiceAntiAffinityPriority(serviceLister ServiceLister, label string) P
}
func (s *ServiceAntiAffinity) CalculateAntiAffinityPriority(pod api.Pod, podLister PodLister, minionLister MinionLister) (HostPriorityList, error) {
var service api.Service
var pods []api.Pod
var err error
service, err = s.serviceLister.GetPodService(pod)
services, err := s.serviceLister.GetPodServices(pod)
if err == nil {
selector := labels.SelectorFromSet(service.Spec.Selector)
// just use the first service and get the other pods within the service
// TODO: a separate predicate can be created that tries to handle all services for the pod
selector := labels.SelectorFromSet(services[0].Spec.Selector)
pods, err = podLister.ListPods(selector)
if err != nil {
return nil, err
@@ -112,43 +114,41 @@ func (s *ServiceAntiAffinity) CalculateAntiAffinityPriority(pod api.Pod, podList
return nil, err
}
// find the zones that the minions belong to
openMinions := []string{}
zonedMinions := map[string]string{}
// separate out the minions that have the label from the ones that don't
otherMinions := []string{}
labeledMinions := map[string]string{}
for _, minion := range minions.Items {
if labels.Set(minion.Labels).Has(s.label) {
zone := labels.Set(minion.Labels).Get(s.label)
zonedMinions[minion.Name] = zone
label := labels.Set(minion.Labels).Get(s.label)
labeledMinions[minion.Name] = label
} else {
openMinions = append(openMinions, minion.Name)
otherMinions = append(otherMinions, minion.Name)
}
}
podCounts := map[string]int{}
numServicePods := len(pods)
if numServicePods > 0 {
for _, pod := range pods {
zone, exists := zonedMinions[pod.Status.Host]
if !exists {
continue
}
podCounts[zone]++
for _, pod := range pods {
zone, exists := labeledMinions[pod.Status.Host]
if !exists {
continue
}
podCounts[zone]++
}
numServicePods := len(pods)
result := []HostPriority{}
//score int - scale of 0-10
// 0 being the lowest priority and 10 being the highest
for minion := range zonedMinions {
for minion := range labeledMinions {
// initializing to the default/max minion score of 10
fScore := float32(10)
if numServicePods > 0 {
fScore = 10 * (float32(numServicePods-podCounts[zonedMinions[minion]]) / float32(numServicePods))
fScore = 10 * (float32(numServicePods-podCounts[labeledMinions[minion]]) / float32(numServicePods))
}
result = append(result, HostPriority{host: minion, score: int(fScore)})
}
// add the open minions with a score of 0
for _, minion := range openMinions {
for _, minion := range otherMinions {
result = append(result, HostPriority{host: minion, score: 0})
}