func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *api.Node, ds *extensions.DaemonSet) bool { // If the daemon set specifies a node name, check that it matches with node.Name. if !(ds.Spec.Template.Spec.NodeName == "" || ds.Spec.Template.Spec.NodeName == node.Name) { return false } // TODO: Move it to the predicates for _, c := range node.Status.Conditions { if c.Type == api.NodeOutOfDisk && c.Status == api.ConditionTrue { return false } } newPod := &api.Pod{Spec: ds.Spec.Template.Spec, ObjectMeta: ds.Spec.Template.ObjectMeta} newPod.Spec.NodeName = node.Name pods := []*api.Pod{} for _, m := range dsc.podStore.Indexer.List() { pod := m.(*api.Pod) if pod.Spec.NodeName != node.Name { continue } if pod.Status.Phase == api.PodSucceeded || pod.Status.Phase == api.PodFailed { continue } // ignore pods that belong to the daemonset when taking into account whether // a daemonset should bind to a node. if pds := dsc.getPodDaemonSet(pod); pds != nil && ds.Name == pds.Name { continue } pods = append(pods, pod) } nodeInfo := schedulercache.NewNodeInfo(pods...) nodeInfo.SetNode(node) fit, reasons, err := predicates.GeneralPredicates(newPod, nil, nodeInfo) if err != nil { glog.Warningf("GeneralPredicates failed on pod %s due to unexpected error: %v", newPod.Name, err) } for _, r := range reasons { glog.V(2).Infof("GeneralPredicates failed on pod %s for reason: %v", newPod.Name, r.GetReason()) } if !fit { return false } fit, reasons, err = predicates.PodToleratesNodeTaints(newPod, predicates.PredicateMetadata(newPod, nil), nodeInfo) if err != nil { glog.Warningf("PodToleratesNodeTaints failed on pod %s due to unexpected error: %v", newPod.Name, err) } for _, r := range reasons { glog.V(2).Infof("PodToleratesNodeTaints failed on pod %s for reason: %v", newPod.Name, r.GetReason()) } return fit }
func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *extensions.DaemonSet) bool { // If the daemon set specifies a node name, check that it matches with node.Name. if !(ds.Spec.Template.Spec.NodeName == "" || ds.Spec.Template.Spec.NodeName == node.Name) { return false } // TODO: Move it to the predicates for _, c := range node.Status.Conditions { if c.Type == v1.NodeOutOfDisk && c.Status == v1.ConditionTrue { return false } } newPod := &v1.Pod{Spec: ds.Spec.Template.Spec, ObjectMeta: ds.Spec.Template.ObjectMeta} newPod.Namespace = ds.Namespace newPod.Spec.NodeName = node.Name pods := []*v1.Pod{} for _, m := range dsc.podStore.Indexer.List() { pod := m.(*v1.Pod) if pod.Spec.NodeName != node.Name { continue } if pod.Status.Phase == v1.PodSucceeded || pod.Status.Phase == v1.PodFailed { continue } // ignore pods that belong to the daemonset when taking into account whether // a daemonset should bind to a node. if pds := dsc.getPodDaemonSet(pod); pds != nil && ds.Name == pds.Name { continue } pods = append(pods, pod) } nodeInfo := schedulercache.NewNodeInfo(pods...) nodeInfo.SetNode(node) fit, reasons, err := predicates.GeneralPredicates(newPod, nil, nodeInfo) if err != nil { glog.Warningf("GeneralPredicates failed on ds '%s/%s' due to unexpected error: %v", ds.ObjectMeta.Namespace, ds.ObjectMeta.Name, err) } for _, r := range reasons { glog.V(4).Infof("GeneralPredicates failed on ds '%s/%s' for reason: %v", ds.ObjectMeta.Namespace, ds.ObjectMeta.Name, r.GetReason()) switch reason := r.(type) { case *predicates.InsufficientResourceError: dsc.eventRecorder.Eventf(ds, v1.EventTypeNormal, "FailedPlacement", "failed to place pod on %q: %s", node.ObjectMeta.Name, reason.Error()) case *predicates.PredicateFailureError: if reason == predicates.ErrPodNotFitsHostPorts { dsc.eventRecorder.Eventf(ds, v1.EventTypeNormal, "FailedPlacement", "failed to place pod on %q: host port conflict", node.ObjectMeta.Name) } } } return fit }
func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *api.Node, ds *extensions.DaemonSet) bool { // If the daemon set specifies a node name, check that it matches with node.Name. if !(ds.Spec.Template.Spec.NodeName == "" || ds.Spec.Template.Spec.NodeName == node.Name) { return false } // TODO: Move it to the predicates for _, c := range node.Status.Conditions { if c.Type == api.NodeOutOfDisk && c.Status == api.ConditionTrue { return false } } newPod := &api.Pod{Spec: ds.Spec.Template.Spec, ObjectMeta: ds.Spec.Template.ObjectMeta} newPod.Spec.NodeName = node.Name pods := []*api.Pod{} for _, m := range dsc.podStore.Indexer.List() { pod := m.(*api.Pod) if pod.Spec.NodeName != node.Name { continue } if pod.Status.Phase == api.PodSucceeded || pod.Status.Phase == api.PodFailed { continue } // ignore pods that belong to the daemonset when taking into account wheter // a daemonset should bind to a node. if pds := dsc.getPodDaemonSet(pod); pds != nil && ds.Name == pds.Name { continue } pods = append(pods, pod) } nodeInfo := schedulercache.NewNodeInfo(pods...) nodeInfo.SetNode(node) fit, err := predicates.GeneralPredicates(newPod, nil, nodeInfo) if err != nil { if re, ok := err.(*predicates.PredicateFailureError); ok { message := re.Error() glog.V(2).Infof("Predicate failed on Pod: %s, for reason: %v", newPod.Name, message) } if re, ok := err.(*predicates.InsufficientResourceError); ok { message := re.Error() glog.V(2).Infof("Predicate failed on Pod: %s, for reason: %v", newPod.Name, message) } message := fmt.Sprintf("GeneralPredicates failed due to %v.", err) glog.Warningf("Predicate failed on Pod %s - %s", newPod.Name, message) } return fit }
// CheckPredicates Checks if the given pod can be placed on the given node. func (p *PredicateChecker) CheckPredicates(pod *kube_api.Pod, nodeInfo *schedulercache.NodeInfo) error { // TODO(fgrzadkowski): Use full list of predicates. match, err := predicates.GeneralPredicates(pod, nodeInfo) nodename := "unknown" if nodeInfo.Node() != nil { nodename = nodeInfo.Node().Name } if err != nil { return fmt.Errorf("cannot put %s on %s due to %v", pod.Name, nodename, err) } if !match { return fmt.Errorf("cannot put %s on %s", pod.Name, nodename) } return nil }
func defaultPredicates() sets.String { return sets.NewString( // Fit is determined by non-conflicting disk volumes. factory.RegisterFitPredicate("NoDiskConflict", predicates.NoDiskConflict), // Fit is determined by volume zone requirements. factory.RegisterFitPredicateFactory( "NoVolumeZoneConflict", func(args factory.PluginFactoryArgs) algorithm.FitPredicate { return predicates.NewVolumeZonePredicate(args.NodeInfo, args.PVInfo, args.PVCInfo) }, ), // Fit is determined by node selector query. factory.RegisterFitPredicateFactory( "MatchNodeSelector", func(args factory.PluginFactoryArgs) algorithm.FitPredicate { return predicates.NewSelectorMatchPredicate(args.NodeInfo) }, ), // Fit is determined by whether or not there would be too many AWS EBS volumes attached to the node factory.RegisterFitPredicateFactory( "MaxEBSVolumeCount", func(args factory.PluginFactoryArgs) algorithm.FitPredicate { // TODO: allow for generically parameterized scheduler predicates, because this is a bit ugly maxVols := getMaxVols(aws.DefaultMaxEBSVolumes) return predicates.NewMaxPDVolumeCountPredicate(predicates.EBSVolumeFilter, maxVols, args.PVInfo, args.PVCInfo) }, ), // Fit is determined by whether or not there would be too many GCE PD volumes attached to the node factory.RegisterFitPredicateFactory( "MaxGCEPDVolumeCount", func(args factory.PluginFactoryArgs) algorithm.FitPredicate { // TODO: allow for generically parameterized scheduler predicates, because this is a bit ugly maxVols := getMaxVols(DefaultMaxGCEPDVolumes) return predicates.NewMaxPDVolumeCountPredicate(predicates.GCEPDVolumeFilter, maxVols, args.PVInfo, args.PVCInfo) }, ), // GeneralPredicates are the predicates that are enforced by all Kubernetes components // (e.g. kubelet and all schedulers) factory.RegisterFitPredicateFactory( "GeneralPredicates", func(args factory.PluginFactoryArgs) algorithm.FitPredicate { return predicates.GeneralPredicates(args.NodeInfo) }, ), ) }
// nodeShouldRunDaemonPod checks a set of preconditions against a (node,daemonset) and returns a // summary. Returned booleans are: // * wantToRun: // Returns true when a user would expect a pod to run on this node and ignores conditions // such as OutOfDisk or insufficent resource that would cause a daemonset pod not to schedule. // This is primarily used to populate daemonset status. // * shouldSchedule: // Returns true when a daemonset should be scheduled to a node if a daemonset pod is not already // running on that node. // * shouldContinueRunning: // Returns true when a daemonset should continue running on a node if a daemonset pod is already // running on that node. func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *extensions.DaemonSet) (wantToRun, shouldSchedule, shouldContinueRunning bool, err error) { // Because these bools require an && of all their required conditions, we start // with all bools set to true and set a bool to false if a condition is not met. // A bool should probably not be set to true after this line. wantToRun, shouldSchedule, shouldContinueRunning = true, true, true // If the daemon set specifies a node name, check that it matches with node.Name. if !(ds.Spec.Template.Spec.NodeName == "" || ds.Spec.Template.Spec.NodeName == node.Name) { return false, false, false, nil } // TODO: Move it to the predicates for _, c := range node.Status.Conditions { if c.Type == v1.NodeOutOfDisk && c.Status == v1.ConditionTrue { // the kubelet will evict this pod if it needs to. Let kubelet // decide whether to continue running this pod so leave shouldContinueRunning // set to true shouldSchedule = false } } newPod := &v1.Pod{Spec: ds.Spec.Template.Spec, ObjectMeta: ds.Spec.Template.ObjectMeta} newPod.Namespace = ds.Namespace newPod.Spec.NodeName = node.Name pods := []*v1.Pod{} for _, m := range dsc.podStore.Indexer.List() { pod := m.(*v1.Pod) if pod.Spec.NodeName != node.Name { continue } if pod.Status.Phase == v1.PodSucceeded || pod.Status.Phase == v1.PodFailed { continue } // ignore pods that belong to the daemonset when taking into account whether // a daemonset should bind to a node. if pds := dsc.getPodDaemonSet(pod); pds != nil && ds.Name == pds.Name { continue } pods = append(pods, pod) } nodeInfo := schedulercache.NewNodeInfo(pods...) nodeInfo.SetNode(node) _, reasons, err := predicates.GeneralPredicates(newPod, nil, nodeInfo) if err != nil { glog.Warningf("GeneralPredicates failed on ds '%s/%s' due to unexpected error: %v", ds.ObjectMeta.Namespace, ds.ObjectMeta.Name, err) return false, false, false, err } for _, r := range reasons { glog.V(4).Infof("GeneralPredicates failed on ds '%s/%s' for reason: %v", ds.ObjectMeta.Namespace, ds.ObjectMeta.Name, r.GetReason()) switch reason := r.(type) { case *predicates.InsufficientResourceError: dsc.eventRecorder.Eventf(ds, v1.EventTypeNormal, "FailedPlacement", "failed to place pod on %q: %s", node.ObjectMeta.Name, reason.Error()) shouldSchedule = false case *predicates.PredicateFailureError: var emitEvent bool // we try to partition predicates into two partitions here: intentional on the part of the operator and not. switch reason { // intentional case predicates.ErrNodeSelectorNotMatch, predicates.ErrPodNotMatchHostName, predicates.ErrNodeLabelPresenceViolated, // this one is probably intentional since it's a workaround for not having // pod hard anti affinity. predicates.ErrPodNotFitsHostPorts: wantToRun, shouldSchedule, shouldContinueRunning = false, false, false // unintentional case predicates.ErrDiskConflict, predicates.ErrVolumeZoneConflict, predicates.ErrMaxVolumeCountExceeded, predicates.ErrNodeUnderMemoryPressure, predicates.ErrNodeUnderDiskPressure: // wantToRun and shouldContinueRunning are likely true here. They are // absolutely true at the time of writing the comment. See first comment // of this method. shouldSchedule = false emitEvent = true // unexpected case predicates.ErrPodAffinityNotMatch, predicates.ErrServiceAffinityViolated, predicates.ErrTaintsTolerationsNotMatch: return false, false, false, fmt.Errorf("unexpected reason: GeneralPredicates should not return reason %s", reason.GetReason()) default: glog.V(4).Infof("unknownd predicate failure reason: %s", reason.GetReason()) wantToRun, shouldSchedule, shouldContinueRunning = false, false, false emitEvent = true } if emitEvent { dsc.eventRecorder.Eventf(ds, v1.EventTypeNormal, "FailedPlacement", "failed to place pod on %q: %s", node.ObjectMeta.Name, reason.GetReason()) } } } return }
func (w *predicateAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult { node, err := w.getNodeAnyWayFunc() if err != nil { glog.Errorf("Cannot get Node info: %v", err) return PodAdmitResult{ Admit: false, Reason: "InvalidNodeInfo", Message: "Kubelet cannot get node info.", } } pod := attrs.Pod pods := attrs.OtherPods nodeInfo := schedulercache.NewNodeInfo(pods...) nodeInfo.SetNode(node) fit, reasons, err := predicates.GeneralPredicates(pod, nil, nodeInfo) if err != nil { message := fmt.Sprintf("GeneralPredicates failed due to %v, which is unexpected.", err) glog.Warningf("Failed to admit pod %v - %s", format.Pod(pod), message) return PodAdmitResult{ Admit: fit, Reason: "UnexpectedError", Message: message, } } if !fit { var reason string var message string if len(reasons) == 0 { message = fmt.Sprint("GeneralPredicates failed due to unknown reason, which is unexpected.") glog.Warningf("Failed to admit pod %v - %s", format.Pod(pod), message) return PodAdmitResult{ Admit: fit, Reason: "UnknownReason", Message: message, } } // If there are failed predicates, we only return the first one as a reason. r := reasons[0] switch re := r.(type) { case *predicates.PredicateFailureError: reason = re.PredicateName message = re.Error() glog.V(2).Infof("Predicate failed on Pod: %v, for reason: %v", format.Pod(pod), message) case *predicates.InsufficientResourceError: reason = fmt.Sprintf("OutOf%s", re.ResourceName) message = re.Error() glog.V(2).Infof("Predicate failed on Pod: %v, for reason: %v", format.Pod(pod), message) case *predicates.FailureReason: reason = re.GetReason() message = fmt.Sprintf("Failure: %s", re.GetReason()) glog.V(2).Infof("Predicate failed on Pod: %v, for reason: %v", format.Pod(pod), message) default: reason = "UnexpectedPredicateFailureType" message = fmt.Sprintf("GeneralPredicates failed due to %v, which is unexpected.", r) glog.Warningf("Failed to admit pod %v - %s", format.Pod(pod), message) } return PodAdmitResult{ Admit: fit, Reason: reason, Message: message, } } return PodAdmitResult{ Admit: true, } }