Change taint/toleration annotations to api fields.

This commit is contained in:
Avesh Agarwal 2017-02-20 11:43:05 -05:00
parent eef16cf141
commit 9b640838a5
22 changed files with 116 additions and 378 deletions

View File

@ -17,7 +17,6 @@ limitations under the License.
package master package master
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"path" "path"
@ -203,9 +202,6 @@ func getAPIServerDS(cfg *kubeadmapi.MasterConfiguration, volumes []v1.Volume, vo
"component": kubeAPIServer, "component": kubeAPIServer,
"tier": "control-plane", "tier": "control-plane",
}, },
Annotations: map[string]string{
v1.TolerationsAnnotationKey: getMasterToleration(),
},
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
NodeSelector: map[string]string{metav1.NodeLabelKubeadmAlphaRole: metav1.NodeLabelRoleMaster}, NodeSelector: map[string]string{metav1.NodeLabelKubeadmAlphaRole: metav1.NodeLabelRoleMaster},
@ -222,6 +218,7 @@ func getAPIServerDS(cfg *kubeadmapi.MasterConfiguration, volumes []v1.Volume, vo
Resources: componentResources("250m"), Resources: componentResources("250m"),
}, },
}, },
Tolerations: getMasterToleration(),
}, },
}, },
}, },
@ -256,9 +253,6 @@ func getControllerManagerDeployment(cfg *kubeadmapi.MasterConfiguration, volumes
"component": kubeControllerManager, "component": kubeControllerManager,
"tier": "control-plane", "tier": "control-plane",
}, },
Annotations: map[string]string{
v1.TolerationsAnnotationKey: getMasterToleration(),
},
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
NodeSelector: map[string]string{metav1.NodeLabelKubeadmAlphaRole: metav1.NodeLabelRoleMaster}, NodeSelector: map[string]string{metav1.NodeLabelKubeadmAlphaRole: metav1.NodeLabelRoleMaster},
@ -275,7 +269,8 @@ func getControllerManagerDeployment(cfg *kubeadmapi.MasterConfiguration, volumes
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, },
}, },
DNSPolicy: v1.DNSDefault, Tolerations: getMasterToleration(),
DNSPolicy: v1.DNSDefault,
}, },
}, },
}, },
@ -310,9 +305,6 @@ func getSchedulerDeployment(cfg *kubeadmapi.MasterConfiguration) ext.Deployment
"component": kubeScheduler, "component": kubeScheduler,
"tier": "control-plane", "tier": "control-plane",
}, },
Annotations: map[string]string{
v1.TolerationsAnnotationKey: getMasterToleration(),
},
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
NodeSelector: map[string]string{metav1.NodeLabelKubeadmAlphaRole: metav1.NodeLabelRoleMaster}, NodeSelector: map[string]string{metav1.NodeLabelKubeadmAlphaRole: metav1.NodeLabelRoleMaster},
@ -327,6 +319,7 @@ func getSchedulerDeployment(cfg *kubeadmapi.MasterConfiguration) ext.Deployment
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, },
}, },
Tolerations: getMasterToleration(),
}, },
}, },
}, },
@ -338,15 +331,14 @@ func buildStaticManifestFilepath(name string) string {
return path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests", name+".yaml") return path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests", name+".yaml")
} }
func getMasterToleration() string { func getMasterToleration() []v1.Toleration {
// Tolerate the master taint we add to our master nodes, as this can and should // Tolerate the master taint we add to our master nodes, as this can and should
// run there. // run there.
// TODO: Duplicated above // TODO: Duplicated above
masterToleration, _ := json.Marshal([]v1.Toleration{{ return []v1.Toleration{{
Key: "dedicated", Key: "dedicated",
Value: "master", Value: "master",
Operator: v1.TolerationOpEqual, Operator: v1.TolerationOpEqual,
Effect: v1.TaintEffectNoSchedule, Effect: v1.TaintEffectNoSchedule,
}}) }}
return string(masterToleration)
} }

View File

@ -59,9 +59,6 @@ spec:
k8s-app: kube-discovery k8s-app: kube-discovery
# TODO: I guess we can remove all these cluster-service labels... # TODO: I guess we can remove all these cluster-service labels...
kubernetes.io/cluster-service: "true" kubernetes.io/cluster-service: "true"
annotations:
# TODO: Move this to the beta tolerations field below as soon as the Tolerations field exists in PodSpec
scheduler.alpha.kubernetes.io/tolerations: '[{"key":"dedicated","value":"master","effect":"NoSchedule"}]'
spec: spec:
containers: containers:
- name: kube-discovery - name: kube-discovery
@ -78,10 +75,10 @@ spec:
name: clusterinfo name: clusterinfo
readOnly: true readOnly: true
hostNetwork: true hostNetwork: true
# tolerations: tolerations:
# - key: dedicated - key: "dedicated"
# value: master value: "master"
# effect: NoSchedule effect: "NoSchedule"
securityContext: securityContext:
seLinuxOptions: seLinuxOptions:
type: spc_t type: spc_t

View File

@ -63,9 +63,6 @@ spec:
metadata: metadata:
labels: labels:
k8s-app: kube-proxy k8s-app: kube-proxy
annotations:
# TODO: Move this to the beta tolerations field below as soon as the Tolerations field exists in PodSpec
scheduler.alpha.kubernetes.io/tolerations: '[{"key":"dedicated","value":"master","effect":"NoSchedule"}]'
spec: spec:
containers: containers:
- name: kube-proxy - name: kube-proxy
@ -82,11 +79,10 @@ spec:
name: kube-proxy name: kube-proxy
hostNetwork: true hostNetwork: true
serviceAccountName: kube-proxy serviceAccountName: kube-proxy
# Tolerate running on the master tolerations:
# tolerations: - key: dedicated
# - key: dedicated value: master
# value: master effect: NoSchedule
# effect: NoSchedule
volumes: volumes:
- name: kube-proxy - name: kube-proxy
configMap: configMap:
@ -122,8 +118,6 @@ spec:
k8s-app: kube-dns k8s-app: kube-dns
annotations: annotations:
scheduler.alpha.kubernetes.io/critical-pod: '' scheduler.alpha.kubernetes.io/critical-pod: ''
# TODO: Move this to the beta tolerations field below as soon as the Tolerations field exists in PodSpec
scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}, {"key":"dedicated","value":"master","effect":"NoSchedule"}]'
spec: spec:
volumes: volumes:
- name: kube-dns-config - name: kube-dns-config
@ -242,10 +236,12 @@ spec:
cpu: 10m cpu: 10m
dnsPolicy: Default # Don't use cluster DNS. dnsPolicy: Default # Don't use cluster DNS.
serviceAccountName: kube-dns serviceAccountName: kube-dns
# tolerations: tolerations:
# - key: dedicated - key: "CriticalAddonsOnly"
# value: master operator: "Exists"
# effect: NoSchedule - key: "dedicated"
value: "master"
effect: "NoSchedule"
# TODO: Remove this affinity field as soon as we are using manifest lists # TODO: Remove this affinity field as soon as we are using manifest lists
affinity: affinity:
nodeAffinity: nodeAffinity:

View File

@ -61,9 +61,7 @@ func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset) error
// TODO: Switch to the new master label defined in https://github.com/kubernetes/kubernetes/pull/39112 // TODO: Switch to the new master label defined in https://github.com/kubernetes/kubernetes/pull/39112
n.ObjectMeta.Labels[metav1.NodeLabelKubeadmAlphaRole] = metav1.NodeLabelRoleMaster n.ObjectMeta.Labels[metav1.NodeLabelKubeadmAlphaRole] = metav1.NodeLabelRoleMaster
// TODO: Use the Taints beta field on the NodeSpec now n.Spec.Taints = []v1.Taint{{Key: "dedicated", Value: "master", Effect: "NoSchedule"}}
taintsAnnotation, _ := json.Marshal([]v1.Taint{{Key: "dedicated", Value: "master", Effect: "NoSchedule"}})
n.ObjectMeta.Annotations[v1.TaintsAnnotationKey] = string(taintsAnnotation)
newData, err := json.Marshal(n) newData, err := json.Marshal(n)
if err != nil { if err != nil {

View File

@ -429,14 +429,6 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
} }
const ( const (
// TolerationsAnnotationKey represents the key of tolerations data (json serialized)
// in the Annotations of a Pod.
TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations"
// TaintsAnnotationKey represents the key of taints data (json serialized)
// in the Annotations of a Node.
TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"
// SeccompPodAnnotationKey represents the key of a seccomp profile applied // SeccompPodAnnotationKey represents the key of a seccomp profile applied
// to all containers of a pod. // to all containers of a pod.
SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod" SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"

View File

@ -21,18 +21,6 @@ import "encoding/json"
// This file implements json marshaling/unmarshaling interfaces on objects that are currently marshaled into annotations // This file implements json marshaling/unmarshaling interfaces on objects that are currently marshaled into annotations
// to prevent anyone from marshaling these internal structs. // to prevent anyone from marshaling these internal structs.
var _ = json.Marshaler(Taint{})
var _ = json.Unmarshaler(&Taint{})
func (Taint) MarshalJSON() ([]byte, error) { panic("do not marshal internal struct") }
func (*Taint) UnmarshalJSON([]byte) error { panic("do not unmarshal to internal struct") }
var _ = json.Marshaler(Toleration{})
var _ = json.Unmarshaler(&Toleration{})
func (Toleration) MarshalJSON() ([]byte, error) { panic("do not marshal internal struct") }
func (*Toleration) UnmarshalJSON([]byte) error { panic("do not unmarshal to internal struct") }
var _ = json.Marshaler(&AvoidPods{}) var _ = json.Marshaler(&AvoidPods{})
var _ = json.Unmarshaler(&AvoidPods{}) var _ = json.Unmarshaler(&AvoidPods{})

View File

@ -2001,6 +2001,9 @@ type PodSpec struct {
// If not specified, the pod will be dispatched by default scheduler. // If not specified, the pod will be dispatched by default scheduler.
// +optional // +optional
SchedulerName string SchedulerName string
// If specified, the pod's tolerations.
// +optional
Tolerations []Toleration
} }
// Sysctl defines a kernel parameter to be set // Sysctl defines a kernel parameter to be set
@ -2623,6 +2626,10 @@ type NodeSpec struct {
// Unschedulable controls node schedulability of new pods. By default node is schedulable. // Unschedulable controls node schedulability of new pods. By default node is schedulable.
// +optional // +optional
Unschedulable bool Unschedulable bool
// If specified, the node's taints.
// +optional
Taints []Taint
} }
// DaemonEndpoint contains information about a single Daemon endpoint. // DaemonEndpoint contains information about a single Daemon endpoint.

View File

@ -235,14 +235,6 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
} }
const ( const (
// TolerationsAnnotationKey represents the key of tolerations data (json serialized)
// in the Annotations of a Pod.
TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations"
// TaintsAnnotationKey represents the key of taints data (json serialized)
// in the Annotations of a Node.
TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"
// SeccompPodAnnotationKey represents the key of a seccomp profile applied // SeccompPodAnnotationKey represents the key of a seccomp profile applied
// to all containers of a pod. // to all containers of a pod.
SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod" SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
@ -284,79 +276,34 @@ const (
AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity" AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
) )
// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
// and converts it to the []Toleration type in api.
func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
var tolerations []Toleration
if len(annotations) > 0 && annotations[TolerationsAnnotationKey] != "" {
err := json.Unmarshal([]byte(annotations[TolerationsAnnotationKey]), &tolerations)
if err != nil {
return tolerations, err
}
}
return tolerations, nil
}
func GetPodTolerations(pod *Pod) ([]Toleration, error) {
return GetTolerationsFromPodAnnotations(pod.Annotations)
}
// Tries to add a toleration to annotations list. Returns true if something was updated // Tries to add a toleration to annotations list. Returns true if something was updated
// false otherwise. // false otherwise.
func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) (bool, error) { func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) (bool, error) {
podTolerations, err := GetPodTolerations(pod) podTolerations := pod.Spec.Tolerations
if err != nil {
return false, err
}
var newTolerations []*Toleration var newTolerations []Toleration
updated := false updated := false
for i := range podTolerations { for i := range podTolerations {
if toleration.MatchToleration(&podTolerations[i]) { if toleration.MatchToleration(&podTolerations[i]) {
if api.Semantic.DeepEqual(toleration, podTolerations[i]) { if api.Semantic.DeepEqual(toleration, podTolerations[i]) {
return false, nil return false, nil
} }
newTolerations = append(newTolerations, toleration) newTolerations = append(newTolerations, *toleration)
updated = true updated = true
continue continue
} }
newTolerations = append(newTolerations, &podTolerations[i]) newTolerations = append(newTolerations, podTolerations[i])
} }
if !updated { if !updated {
newTolerations = append(newTolerations, toleration) newTolerations = append(newTolerations, *toleration)
} }
tolerationsData, err := json.Marshal(newTolerations) pod.Spec.Tolerations = newTolerations
if err != nil {
return false, err
}
if pod.Annotations == nil {
pod.Annotations = make(map[string]string)
}
pod.Annotations[TolerationsAnnotationKey] = string(tolerationsData)
return true, nil return true, nil
} }
// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations
// and converts it to the []Taint type in api.
func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]Taint, error) {
var taints []Taint
if len(annotations) > 0 && annotations[TaintsAnnotationKey] != "" {
err := json.Unmarshal([]byte(annotations[TaintsAnnotationKey]), &taints)
if err != nil {
return []Taint{}, err
}
}
return taints, nil
}
func GetNodeTaints(node *Node) ([]Taint, error) {
return GetTaintsFromNodeAnnotations(node.Annotations)
}
// MatchToleration checks if the toleration matches tolerationToMatch. Tolerations are unique by <key,effect,operator,value>, // MatchToleration checks if the toleration matches tolerationToMatch. Tolerations are unique by <key,effect,operator,value>,
// if the two tolerations have same <key,effect,operator,value> combination, regard as they match. // if the two tolerations have same <key,effect,operator,value> combination, regard as they match.
// TODO: uniqueness check for tolerations in api validations. // TODO: uniqueness check for tolerations in api validations.
@ -574,39 +521,28 @@ func AddOrUpdateTaint(node *Node, taint *Taint) (*Node, bool, error) {
return nil, false, err return nil, false, err
} }
newNode := objCopy.(*Node) newNode := objCopy.(*Node)
nodeTaints, err := GetTaintsFromNodeAnnotations(newNode.Annotations) nodeTaints := newNode.Spec.Taints
if err != nil {
return newNode, false, err
}
var newTaints []*Taint var newTaints []Taint
updated := false updated := false
for i := range nodeTaints { for i := range nodeTaints {
if taint.MatchTaint(&nodeTaints[i]) { if taint.MatchTaint(&nodeTaints[i]) {
if api.Semantic.DeepEqual(taint, nodeTaints[i]) { if api.Semantic.DeepEqual(taint, nodeTaints[i]) {
return newNode, false, nil return newNode, false, nil
} }
newTaints = append(newTaints, taint) newTaints = append(newTaints, *taint)
updated = true updated = true
continue continue
} }
newTaints = append(newTaints, &nodeTaints[i]) newTaints = append(newTaints, nodeTaints[i])
} }
if !updated { if !updated {
newTaints = append(newTaints, taint) newTaints = append(newTaints, *taint)
} }
taintsData, err := json.Marshal(newTaints) newNode.Spec.Taints = newTaints
if err != nil {
return nil, false, err
}
if newNode.Annotations == nil {
newNode.Annotations = make(map[string]string)
}
newNode.Annotations[TaintsAnnotationKey] = string(taintsData)
return newNode, true, nil return newNode, true, nil
} }
@ -627,10 +563,7 @@ func RemoveTaint(node *Node, taint *Taint) (*Node, bool, error) {
return nil, false, err return nil, false, err
} }
newNode := objCopy.(*Node) newNode := objCopy.(*Node)
nodeTaints, err := GetTaintsFromNodeAnnotations(newNode.Annotations) nodeTaints := newNode.Spec.Taints
if err != nil {
return newNode, false, err
}
if len(nodeTaints) == 0 { if len(nodeTaints) == 0 {
return newNode, false, nil return newNode, false, nil
} }
@ -640,15 +573,7 @@ func RemoveTaint(node *Node, taint *Taint) (*Node, bool, error) {
} }
newTaints, _ := DeleteTaint(nodeTaints, taint) newTaints, _ := DeleteTaint(nodeTaints, taint)
if len(newTaints) == 0 { newNode.Spec.Taints = newTaints
delete(newNode.Annotations, TaintsAnnotationKey)
} else {
taintsData, err := json.Marshal(newTaints)
if err != nil {
return newNode, false, err
}
newNode.Annotations[TaintsAnnotationKey] = string(taintsData)
}
return newNode, true, nil return newNode, true, nil
} }

View File

@ -2286,6 +2286,9 @@ type PodSpec struct {
// If not specified, the pod will be dispatched by default scheduler. // If not specified, the pod will be dispatched by default scheduler.
// +optional // +optional
SchedulerName string `json:"schedulername,omitempty" protobuf:"bytes,19,opt,name=schedulername"` SchedulerName string `json:"schedulername,omitempty" protobuf:"bytes,19,opt,name=schedulername"`
// If specified, the pod's tolerations.
// +optional
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
} }
// PodSecurityContext holds pod-level security attributes and common container settings. // PodSecurityContext holds pod-level security attributes and common container settings.
@ -3022,6 +3025,9 @@ type NodeSpec struct {
// More info: http://releases.k8s.io/HEAD/docs/admin/node.md#manual-node-administration // More info: http://releases.k8s.io/HEAD/docs/admin/node.md#manual-node-administration
// +optional // +optional
Unschedulable bool `json:"unschedulable,omitempty" protobuf:"varint,4,opt,name=unschedulable"` Unschedulable bool `json:"unschedulable,omitempty" protobuf:"varint,4,opt,name=unschedulable"`
// If specified, the node's taints.
// +optional
Taints []Taint `json:"taints,omitempty" protobuf:"bytes,5,opt,name=taints"`
} }
// DaemonEndpoint contains information about a single Daemon endpoint. // DaemonEndpoint contains information about a single Daemon endpoint.

View File

@ -105,9 +105,6 @@ func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList
func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList { func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if annotations[api.TolerationsAnnotationKey] != "" {
allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
}
// TODO: remove these after we EOL the annotations. // TODO: remove these after we EOL the annotations.
if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists { if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists {
@ -1948,6 +1945,10 @@ func ValidatePodSpec(spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
allErrs = append(allErrs, ValidateDNS1123Label(spec.Subdomain, fldPath.Child("subdomain"))...) allErrs = append(allErrs, ValidateDNS1123Label(spec.Subdomain, fldPath.Child("subdomain"))...)
} }
if len(spec.Tolerations) > 0 {
allErrs = append(allErrs, validateTolerations(spec.Tolerations, fldPath.Child("tolerations"))...)
}
return allErrs return allErrs
} }
@ -2139,29 +2140,6 @@ func validatePodAffinity(podAffinity *api.PodAffinity, fldPath *field.Path) fiel
return allErrs return allErrs
} }
// ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
v1Tolerations, err := v1.GetTolerationsFromPodAnnotations(annotations)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, api.TolerationsAnnotationKey, err.Error()))
return allErrs
}
tolerations := make([]api.Toleration, len(v1Tolerations))
for i := range v1Tolerations {
if err := v1.Convert_v1_Toleration_To_api_Toleration(&v1Tolerations[i], &tolerations[i], nil); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, api.TolerationsAnnotationKey, err.Error()))
return allErrs
}
}
if len(tolerations) > 0 {
allErrs = append(allErrs, validateTolerations(tolerations, fldPath.Child(api.TolerationsAnnotationKey))...)
}
return allErrs
}
func ValidateSeccompProfile(p string, fldPath *field.Path) field.ErrorList { func ValidateSeccompProfile(p string, fldPath *field.Path) field.ErrorList {
if p == "docker/default" { if p == "docker/default" {
return nil return nil
@ -2813,8 +2791,8 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path)
return allErrs return allErrs
} }
// validateTaints tests if given taints have valid data. // validateNodeTaints tests if given taints have valid data.
func validateTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList { func validateNodeTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList {
allErrors := field.ErrorList{} allErrors := field.ErrorList{}
uniqueTaints := map[api.TaintEffect]sets.String{} uniqueTaints := map[api.TaintEffect]sets.String{}
@ -2847,37 +2825,11 @@ func validateTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList {
return allErrors return allErrors
} }
// ValidateTaintsInNodeAnnotations tests that the serialized taints in Node.Annotations has valid data
func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
v1Taints, err := v1.GetTaintsFromNodeAnnotations(annotations)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, api.TaintsAnnotationKey, err.Error()))
return allErrs
}
taints := make([]api.Taint, len(v1Taints))
for i := range v1Taints {
if err := v1.Convert_v1_Taint_To_api_Taint(&v1Taints[i], &taints[i], nil); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, api.TaintsAnnotationKey, err.Error()))
return allErrs
}
}
if len(taints) > 0 {
allErrs = append(allErrs, validateTaints(taints, fldPath.Child(api.TaintsAnnotationKey))...)
}
return allErrs
}
func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if annotations[api.PreferAvoidPodsAnnotationKey] != "" { if annotations[api.PreferAvoidPodsAnnotationKey] != "" {
allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...) allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...)
} }
if annotations[api.TaintsAnnotationKey] != "" {
allErrs = append(allErrs, ValidateTaintsInNodeAnnotations(annotations, fldPath)...)
}
return allErrs return allErrs
} }
@ -2886,6 +2838,9 @@ func ValidateNode(node *api.Node) field.ErrorList {
fldPath := field.NewPath("metadata") fldPath := field.NewPath("metadata")
allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, fldPath) allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, fldPath)
allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...) allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
if len(node.Spec.Taints) > 0 {
allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, fldPath.Child("taints"))...)
}
// Only validate spec. All status fields are optional and can be updated later. // Only validate spec. All status fields are optional and can be updated later.
@ -2948,10 +2903,16 @@ func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList {
// Clear status // Clear status
oldNode.Status = node.Status oldNode.Status = node.Status
// update taints
if len(node.Spec.Taints) > 0 {
allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, fldPath.Child("taints"))...)
}
oldNode.Spec.Taints = node.Spec.Taints
// TODO: Add a 'real' error type for this error and provide print actual diffs. // TODO: Add a 'real' error type for this error and provide print actual diffs.
if !apiequality.Semantic.DeepEqual(oldNode, node) { if !apiequality.Semantic.DeepEqual(oldNode, node) {
glog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, node) glog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, node)
allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "node updates may only change labels or capacity")) allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "node updates may only change labels, taints or capacity"))
} }
return allErrs return allErrs

View File

@ -280,22 +280,13 @@ func (tc *NoExecuteTaintManager) Run(stopCh <-chan struct{}) {
// PodUpdated is used to notify NoExecuteTaintManager about Pod changes. // PodUpdated is used to notify NoExecuteTaintManager about Pod changes.
func (tc *NoExecuteTaintManager) PodUpdated(oldPod *v1.Pod, newPod *v1.Pod) { func (tc *NoExecuteTaintManager) PodUpdated(oldPod *v1.Pod, newPod *v1.Pod) {
var err error
oldTolerations := []v1.Toleration{} oldTolerations := []v1.Toleration{}
if oldPod != nil { if oldPod != nil {
oldTolerations, err = v1.GetPodTolerations(oldPod) oldTolerations = oldPod.Spec.Tolerations
if err != nil {
glog.Errorf("Failed to get Tolerations from the old Pod: %v", err)
return
}
} }
newTolerations := []v1.Toleration{} newTolerations := []v1.Toleration{}
if newPod != nil { if newPod != nil {
newTolerations, err = v1.GetPodTolerations(newPod) newTolerations = newPod.Spec.Tolerations
if err != nil {
glog.Errorf("Failed to get Tolerations from the new Pod: %v", err)
return
}
} }
if oldPod != nil && newPod != nil && api.Semantic.DeepEqual(oldTolerations, newTolerations) && oldPod.Spec.NodeName == newPod.Spec.NodeName { if oldPod != nil && newPod != nil && api.Semantic.DeepEqual(oldTolerations, newTolerations) && oldPod.Spec.NodeName == newPod.Spec.NodeName {
@ -312,24 +303,15 @@ func (tc *NoExecuteTaintManager) PodUpdated(oldPod *v1.Pod, newPod *v1.Pod) {
// NodeUpdated is used to notify NoExecuteTaintManager about Node changes. // NodeUpdated is used to notify NoExecuteTaintManager about Node changes.
func (tc *NoExecuteTaintManager) NodeUpdated(oldNode *v1.Node, newNode *v1.Node) { func (tc *NoExecuteTaintManager) NodeUpdated(oldNode *v1.Node, newNode *v1.Node) {
var err error
oldTaints := []v1.Taint{} oldTaints := []v1.Taint{}
if oldNode != nil { if oldNode != nil {
oldTaints, err = v1.GetNodeTaints(oldNode) oldTaints = oldNode.Spec.Taints
if err != nil {
glog.Errorf("Failed to get Taints from the old Node: %v", err)
return
}
} }
oldTaints = getNoExecuteTaints(oldTaints) oldTaints = getNoExecuteTaints(oldTaints)
newTaints := []v1.Taint{} newTaints := []v1.Taint{}
if newNode != nil { if newNode != nil {
newTaints, err = v1.GetNodeTaints(newNode) newTaints = newNode.Spec.Taints
if err != nil {
glog.Errorf("Failed to get Taints from the new Node: %v", err)
return
}
} }
newTaints = getNoExecuteTaints(newTaints) newTaints = getNoExecuteTaints(newTaints)
@ -466,12 +448,7 @@ func (tc *NoExecuteTaintManager) handleNodeUpdate(nodeUpdate *nodeUpdateItem) {
for i := range pods { for i := range pods {
pod := &pods[i] pod := &pods[i]
podNamespacedName := types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name} podNamespacedName := types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}
tolerations, err := v1.GetPodTolerations(pod) tc.processPodOnNode(podNamespacedName, node.Name, pod.Spec.Tolerations, taints, now)
if err != nil {
glog.Errorf("Failed to get Tolerations from Pod %v: %v", podNamespacedName.String(), err)
continue
}
tc.processPodOnNode(podNamespacedName, node.Name, tolerations, taints, now)
} }
} }

View File

@ -25,8 +25,6 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
@ -115,18 +113,15 @@ func NewCmdTaint(f cmdutil.Factory, out io.Writer) *cobra.Command {
// reorganizeTaints returns the updated set of taints, taking into account old taints that were not updated, // reorganizeTaints returns the updated set of taints, taking into account old taints that were not updated,
// old taints that were updated, old taints that were deleted, and new taints. // old taints that were updated, old taints that were deleted, and new taints.
func reorganizeTaints(accessor metav1.Object, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) ([]v1.Taint, error) { func reorganizeTaints(obj runtime.Object, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) ([]v1.Taint, error) {
newTaints := append([]v1.Taint{}, taintsToAdd...) node, ok := obj.(*v1.Node)
if !ok {
var oldTaints []v1.Taint return nil, fmt.Errorf("unexpected type %T, expected Node", obj)
var err error
annotations := accessor.GetAnnotations()
if annotations != nil {
if oldTaints, err = v1.GetTaintsFromNodeAnnotations(annotations); err != nil {
return nil, err
}
} }
newTaints := append([]v1.Taint{}, taintsToAdd...)
oldTaints := node.Spec.Taints
// add taints that already existing but not updated to newTaints // add taints that already existing but not updated to newTaints
for _, oldTaint := range oldTaints { for _, oldTaint := range oldTaints {
existsInNew := false existsInNew := false
@ -351,23 +346,18 @@ func (o TaintOptions) RunTaint() error {
} }
// validateNoTaintOverwrites validates that when overwrite is false, to-be-updated taints don't exist in the node taint list (yet) // validateNoTaintOverwrites validates that when overwrite is false, to-be-updated taints don't exist in the node taint list (yet)
func validateNoTaintOverwrites(accessor metav1.Object, taints []v1.Taint) error { func validateNoTaintOverwrites(obj runtime.Object, taints []v1.Taint) error {
annotations := accessor.GetAnnotations() node, ok := obj.(*v1.Node)
if annotations == nil { if !ok {
return nil return fmt.Errorf("unexpected type %T, expected Node", obj)
} }
allErrs := []error{} allErrs := []error{}
oldTaints, err := v1.GetTaintsFromNodeAnnotations(annotations) oldTaints := node.Spec.Taints
if err != nil {
allErrs = append(allErrs, err)
return utilerrors.NewAggregate(allErrs)
}
for _, taint := range taints { for _, taint := range taints {
for _, oldTaint := range oldTaints { for _, oldTaint := range oldTaints {
if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect { if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect {
allErrs = append(allErrs, fmt.Errorf("Node '%s' already has a taint with key (%s) and effect (%v), and --overwrite is false", accessor.GetName(), taint.Key, taint.Effect)) allErrs = append(allErrs, fmt.Errorf("Node '%s' already has a taint with key (%s) and effect (%v), and --overwrite is false", node.Name, taint.Key, taint.Effect))
break break
} }
} }
@ -377,31 +367,22 @@ func validateNoTaintOverwrites(accessor metav1.Object, taints []v1.Taint) error
// updateTaints updates taints of obj // updateTaints updates taints of obj
func (o TaintOptions) updateTaints(obj runtime.Object) error { func (o TaintOptions) updateTaints(obj runtime.Object) error {
accessor, err := meta.Accessor(obj)
if err != nil {
return err
}
if !o.overwrite { if !o.overwrite {
if err := validateNoTaintOverwrites(accessor, o.taintsToAdd); err != nil { if err := validateNoTaintOverwrites(obj, o.taintsToAdd); err != nil {
return err return err
} }
} }
annotations := accessor.GetAnnotations() newTaints, err := reorganizeTaints(obj, o.overwrite, o.taintsToAdd, o.taintsToRemove)
if annotations == nil { if err != nil {
annotations = make(map[string]string) return err
} }
newTaints, err := reorganizeTaints(accessor, o.overwrite, o.taintsToAdd, o.taintsToRemove) node, ok := obj.(*v1.Node)
if err != nil { if !ok {
return err return fmt.Errorf("unexpected type %T, expected Node", obj)
} }
taintsData, err := json.Marshal(newTaints) node.Spec.Taints = newTaints
if err != nil {
return err
}
annotations[v1.TaintsAnnotationKey] = string(taintsData)
accessor.SetAnnotations(annotations)
return nil return nil
} }

View File

@ -45,7 +45,6 @@ import (
"k8s.io/kubernetes/pkg/api/annotations" "k8s.io/kubernetes/pkg/api/annotations"
"k8s.io/kubernetes/pkg/api/events" "k8s.io/kubernetes/pkg/api/events"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/batch"
@ -582,7 +581,7 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) {
describeVolumes(pod.Spec.Volumes, w, "") describeVolumes(pod.Spec.Volumes, w, "")
w.Write(LEVEL_0, "QoS Class:\t%s\n", pod.Status.QOSClass) w.Write(LEVEL_0, "QoS Class:\t%s\n", pod.Status.QOSClass)
printLabelsMultiline(w, "Node-Selectors", pod.Spec.NodeSelector) printLabelsMultiline(w, "Node-Selectors", pod.Spec.NodeSelector)
printTolerationsInAnnotationMultiline(w, "Tolerations", pod.Annotations) printPodTolerationsMultiline(w, "Tolerations", pod.Spec.Tolerations)
if events != nil { if events != nil {
DescribeEvents(events, w) DescribeEvents(events, w)
} }
@ -1987,7 +1986,7 @@ func describeNode(node *api.Node, nodeNonTerminatedPodsList *api.PodList, events
w.Write(LEVEL_0, "Name:\t%s\n", node.Name) w.Write(LEVEL_0, "Name:\t%s\n", node.Name)
w.Write(LEVEL_0, "Role:\t%s\n", findNodeRole(node)) w.Write(LEVEL_0, "Role:\t%s\n", findNodeRole(node))
printLabelsMultiline(w, "Labels", node.Labels) printLabelsMultiline(w, "Labels", node.Labels)
printTaintsInAnnotationMultiline(w, "Taints", node.Annotations) printNodeTaintsMultiline(w, "Taints", node.Spec.Taints)
w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z)) w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z))
w.Write(LEVEL_0, "Phase:\t%v\n", node.Status.Phase) w.Write(LEVEL_0, "Phase:\t%v\n", node.Status.Phase)
if len(node.Status.Conditions) > 0 { if len(node.Status.Conditions) > 0 {
@ -2854,17 +2853,7 @@ func printLabelsMultilineWithIndent(w *PrefixWriter, initialIndent, title, inner
} }
// printTaintsMultiline prints multiple taints with a proper alignment. // printTaintsMultiline prints multiple taints with a proper alignment.
func printTaintsInAnnotationMultiline(w *PrefixWriter, title string, annotations map[string]string) { func printNodeTaintsMultiline(w *PrefixWriter, title string, taints []api.Taint) {
v1Taints, err := v1.GetTaintsFromNodeAnnotations(annotations)
if err != nil {
v1Taints = []v1.Taint{}
}
taints := make([]api.Taint, len(v1Taints))
for i := range v1Taints {
if err := v1.Convert_v1_Taint_To_api_Taint(&v1Taints[i], &taints[i], nil); err != nil {
panic(err)
}
}
printTaintsMultilineWithIndent(w, "", title, "\t", taints) printTaintsMultilineWithIndent(w, "", title, "\t", taints)
} }
@ -2898,18 +2887,8 @@ func printTaintsMultilineWithIndent(w *PrefixWriter, initialIndent, title, inner
} }
} }
// printTolerationsMultiline prints multiple tolerations with a proper alignment. // printPodTolerationsMultiline prints multiple tolerations with a proper alignment.
func printTolerationsInAnnotationMultiline(w *PrefixWriter, title string, annotations map[string]string) { func printPodTolerationsMultiline(w *PrefixWriter, title string, tolerations []api.Toleration) {
v1Tolerations, err := v1.GetTolerationsFromPodAnnotations(annotations)
if err != nil {
v1Tolerations = []v1.Toleration{}
}
tolerations := make([]api.Toleration, len(v1Tolerations))
for i := range v1Tolerations {
if err := v1.Convert_v1_Toleration_To_api_Toleration(&v1Tolerations[i], &tolerations[i], nil); err != nil {
panic(err)
}
}
printTolerationsMultilineWithIndent(w, "", title, "\t", tolerations) printTolerationsMultilineWithIndent(w, "", title, "\t", tolerations)
} }

View File

@ -17,7 +17,6 @@ limitations under the License.
package kubelet package kubelet
import ( import (
"encoding/json"
"fmt" "fmt"
"math" "math"
"net" "net"
@ -204,19 +203,13 @@ func (kl *Kubelet) initialNode() (*v1.Node, error) {
}, },
} }
if len(kl.kubeletConfiguration.RegisterWithTaints) > 0 { if len(kl.kubeletConfiguration.RegisterWithTaints) > 0 {
annotations := make(map[string]string)
taints := make([]v1.Taint, len(kl.kubeletConfiguration.RegisterWithTaints)) taints := make([]v1.Taint, len(kl.kubeletConfiguration.RegisterWithTaints))
for i := range kl.kubeletConfiguration.RegisterWithTaints { for i := range kl.kubeletConfiguration.RegisterWithTaints {
if err := v1.Convert_api_Taint_To_v1_Taint(&kl.kubeletConfiguration.RegisterWithTaints[i], &taints[i], nil); err != nil { if err := v1.Convert_api_Taint_To_v1_Taint(&kl.kubeletConfiguration.RegisterWithTaints[i], &taints[i], nil); err != nil {
return nil, err return nil, err
} }
} }
b, err := json.Marshal(taints) node.Spec.Taints = taints
if err != nil {
return nil, err
}
annotations[v1.TaintsAnnotationKey] = string(b)
node.ObjectMeta.Annotations = annotations
} }
// Initially, set NodeNetworkUnavailable to true. // Initially, set NodeNetworkUnavailable to true.

View File

@ -72,11 +72,7 @@ func (p *plugin) Admit(attributes admission.Attributes) (err error) {
return nil return nil
} }
tolerations, err := v1.GetPodTolerations(pod) tolerations := pod.Spec.Tolerations
if err != nil {
glog.V(5).Infof("Invalid pod tolerations detected, but we will leave handling of this to validation phase")
return nil
}
toleratesNodeNotReady := false toleratesNodeNotReady := false
toleratesNodeUnreachable := false toleratesNodeUnreachable := false

View File

@ -1160,13 +1160,8 @@ func PodToleratesNodeTaints(pod *v1.Pod, meta interface{}, nodeInfo *schedulerca
return false, nil, err return false, nil, err
} }
tolerations, err := v1.GetTolerationsFromPodAnnotations(pod.Annotations) if v1.TolerationsTolerateTaintsWithFilter(pod.Spec.Tolerations, taints, func(t *v1.Taint) bool {
if err != nil { // PodToleratesNodeTaints is only interested in NoSchedule taints.
return false, nil, err
}
if v1.TolerationsTolerateTaintsWithFilter(tolerations, taints, func(t *v1.Taint) bool {
// PodToleratesNodeTaints is only interested in NoSchedule and NoExecute taints.
return t.Effect == v1.TaintEffectNoSchedule || t.Effect == v1.TaintEffectNoExecute return t.Effect == v1.TaintEffectNoSchedule || t.Effect == v1.TaintEffectNoExecute
}) { }) {
return true, nil, nil return true, nil, nil

View File

@ -53,11 +53,7 @@ func getAllTolerationPreferNoSchedule(tolerations []v1.Toleration) (tolerationLi
} }
func getTolerationListFromPod(pod *v1.Pod) ([]v1.Toleration, error) { func getTolerationListFromPod(pod *v1.Pod) ([]v1.Toleration, error) {
tolerations, err := v1.GetTolerationsFromPodAnnotations(pod.Annotations) return getAllTolerationPreferNoSchedule(pod.Spec.Tolerations), nil
if err != nil {
return nil, err
}
return getAllTolerationPreferNoSchedule(tolerations), nil
} }
// ComputeTaintTolerationPriority prepares the priority list for all the nodes based on the number of intolerable taints on the node // ComputeTaintTolerationPriority prepares the priority list for all the nodes based on the number of intolerable taints on the node
@ -78,13 +74,9 @@ func ComputeTaintTolerationPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *
} }
} }
taints, err := v1.GetTaintsFromNodeAnnotations(node.Annotations)
if err != nil {
return schedulerapi.HostPriority{}, err
}
return schedulerapi.HostPriority{ return schedulerapi.HostPriority{
Host: node.Name, Host: node.Name,
Score: countIntolerableTaintsPreferNoSchedule(taints, tolerationList), Score: countIntolerableTaintsPreferNoSchedule(node.Spec.Taints, tolerationList),
}, nil }, nil
} }

View File

@ -337,7 +337,7 @@ func (n *NodeInfo) SetNode(node *v1.Node) error {
} }
} }
} }
n.taints, n.taintsErr = v1.GetTaintsFromNodeAnnotations(node.Annotations) n.taints = node.Spec.Taints
for i := range node.Status.Conditions { for i := range node.Status.Conditions {
cond := &node.Status.Conditions[i] cond := &node.Status.Conditions[i]
switch cond.Type { switch cond.Type {

View File

@ -429,14 +429,6 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
} }
const ( const (
// TolerationsAnnotationKey represents the key of tolerations data (json serialized)
// in the Annotations of a Pod.
TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations"
// TaintsAnnotationKey represents the key of taints data (json serialized)
// in the Annotations of a Node.
TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"
// SeccompPodAnnotationKey represents the key of a seccomp profile applied // SeccompPodAnnotationKey represents the key of a seccomp profile applied
// to all containers of a pod. // to all containers of a pod.
SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod" SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"

View File

@ -1913,6 +1913,9 @@ type PodSpec struct {
// If not specified, the pod will be dispatched by default scheduler. // If not specified, the pod will be dispatched by default scheduler.
// +optional // +optional
SchedulerName string SchedulerName string
// If specified, the pod's tolerations.
// +optional
Tolerations []Toleration
} }
// Sysctl defines a kernel parameter to be set // Sysctl defines a kernel parameter to be set
@ -2530,6 +2533,10 @@ type NodeSpec struct {
// Unschedulable controls node schedulability of new pods. By default node is schedulable. // Unschedulable controls node schedulability of new pods. By default node is schedulable.
// +optional // +optional
Unschedulable bool Unschedulable bool
// If specified, the node's taints.
// +optional
Taints []Taint
} }
// DaemonEndpoint contains information about a single Daemon endpoint. // DaemonEndpoint contains information about a single Daemon endpoint.

View File

@ -234,14 +234,6 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
} }
const ( const (
// TolerationsAnnotationKey represents the key of tolerations data (json serialized)
// in the Annotations of a Pod.
TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations"
// TaintsAnnotationKey represents the key of taints data (json serialized)
// in the Annotations of a Node.
TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"
// SeccompPodAnnotationKey represents the key of a seccomp profile applied // SeccompPodAnnotationKey represents the key of a seccomp profile applied
// to all containers of a pod. // to all containers of a pod.
SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod" SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
@ -278,40 +270,6 @@ const (
ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl" ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
) )
// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
// and converts it to the []Toleration type in api.
func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
var tolerations []Toleration
if len(annotations) > 0 && annotations[TolerationsAnnotationKey] != "" {
err := json.Unmarshal([]byte(annotations[TolerationsAnnotationKey]), &tolerations)
if err != nil {
return tolerations, err
}
}
return tolerations, nil
}
func GetPodTolerations(pod *Pod) ([]Toleration, error) {
return GetTolerationsFromPodAnnotations(pod.Annotations)
}
// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations
// and converts it to the []Taint type in api.
func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]Taint, error) {
var taints []Taint
if len(annotations) > 0 && annotations[TaintsAnnotationKey] != "" {
err := json.Unmarshal([]byte(annotations[TaintsAnnotationKey]), &taints)
if err != nil {
return []Taint{}, err
}
}
return taints, nil
}
func GetNodeTaints(node *Node) ([]Taint, error) {
return GetTaintsFromNodeAnnotations(node.Annotations)
}
// ToleratesTaint checks if the toleration tolerates the taint. // ToleratesTaint checks if the toleration tolerates the taint.
// The matching follows the rules below: // The matching follows the rules below:
// (1) Empty toleration.effect means to match all taint effects, // (1) Empty toleration.effect means to match all taint effects,

View File

@ -2203,6 +2203,9 @@ type PodSpec struct {
// If not specified, the pod will be dispatched by default scheduler. // If not specified, the pod will be dispatched by default scheduler.
// +optional // +optional
SchedulerName string `json:"schedulername,omitempty" protobuf:"bytes,19,opt,name=schedulername"` SchedulerName string `json:"schedulername,omitempty" protobuf:"bytes,19,opt,name=schedulername"`
// If specified, the pod's tolerations.
// +optional
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,21,opt,name=tolerations"`
} }
// PodSecurityContext holds pod-level security attributes and common container settings. // PodSecurityContext holds pod-level security attributes and common container settings.
@ -2934,6 +2937,9 @@ type NodeSpec struct {
// More info: http://releases.k8s.io/HEAD/docs/admin/node.md#manual-node-administration // More info: http://releases.k8s.io/HEAD/docs/admin/node.md#manual-node-administration
// +optional // +optional
Unschedulable bool `json:"unschedulable,omitempty" protobuf:"varint,4,opt,name=unschedulable"` Unschedulable bool `json:"unschedulable,omitempty" protobuf:"varint,4,opt,name=unschedulable"`
// If specified, the node's taints.
// +optional
Taints []Taint `json:"taints,omitempty" protobuf:"bytes,5,opt,name=taints"`
} }
// DaemonEndpoint contains information about a single Daemon endpoint. // DaemonEndpoint contains information about a single Daemon endpoint.