api changes of forgiveness phase1

This commit is contained in:
Kevin 2017-01-04 19:45:50 +08:00
parent 68f123dfa0
commit 72a19819a6
5 changed files with 174 additions and 43 deletions

View File

@ -1783,8 +1783,12 @@ type Taint struct {
Value string Value string
// Required. The effect of the taint on pods // Required. The effect of the taint on pods
// that do not tolerate the taint. // that do not tolerate the taint.
// Valid effects are NoSchedule and PreferNoSchedule. // Valid effects are NoSchedule, PreferNoSchedule and NoExecute.
Effect TaintEffect Effect TaintEffect
// TimeAdded represents the time at which the taint was added.
// It is only written for NoExecute taints.
// +optional
TimeAdded metav1.Time
} }
type TaintEffect string type TaintEffect string
@ -1800,26 +1804,23 @@ const (
// onto the node entirely. Enforced by the scheduler. // onto the node entirely. Enforced by the scheduler.
TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule" TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule"
// NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. // NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented.
// Do not allow new pods to schedule onto the node unless they tolerate the taint, // Like TaintEffectNoSchedule, but additionally do not allow pods submitted to
// do not allow pods to start on Kubelet unless they tolerate the taint, // Kubelet without going through the scheduler to start.
// but allow all already-running pods to continue running. // Enforced by Kubelet and the scheduler.
// Enforced by the scheduler and Kubelet.
// TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit" // TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit"
// NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. // Evict any already-running pods that do not tolerate the taint.
// Do not allow new pods to schedule onto the node unless they tolerate the taint, // Currently enforced by NodeController.
// do not allow pods to start on Kubelet unless they tolerate the taint, TaintEffectNoExecute TaintEffect = "NoExecute"
// and evict any already-running pods that do not tolerate the taint.
// Enforced by the scheduler and Kubelet.
// TaintEffectNoScheduleNoAdmitNoExecute = "NoScheduleNoAdmitNoExecute"
) )
// The pod this Toleration is attached to tolerates any taint that matches // The pod this Toleration is attached to tolerates any taint that matches
// the triple <key,value,effect> using the matching operator <operator>. // the triple <key,value,effect> using the matching operator <operator>.
type Toleration struct { type Toleration struct {
// Required. Key is the taint key that the toleration applies to. // Key is the taint key that the toleration applies to. Empty means match all taint keys.
// If the key is empty, operator must be Exists; this combination means to match all values and all keys.
// +optional // +optional
Key string Key string
// operator represents a key's relationship to the value. // Operator represents a key's relationship to the value.
// Valid operators are Exists and Equal. Defaults to Equal. // Valid operators are Exists and Equal. Defaults to Equal.
// Exists is equivalent to wildcard for value, so that a pod can // Exists is equivalent to wildcard for value, so that a pod can
// tolerate all taints of a particular category. // tolerate all taints of a particular category.
@ -1830,11 +1831,15 @@ type Toleration struct {
// +optional // +optional
Value string Value string
// Effect indicates the taint effect to match. Empty means match all taint effects. // Effect indicates the taint effect to match. Empty means match all taint effects.
// When specified, allowed values are NoSchedule and PreferNoSchedule. // When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
// +optional // +optional
Effect TaintEffect Effect TaintEffect
// TODO: For forgiveness (#1574), we'd eventually add at least a grace period // TolerationSeconds represents the period of time the toleration (which must be
// here, and possibly an occurrence threshold and period. // of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
// it is not set, which means tolerate the taint forever (do not evict). Zero and
// negative values will be treated as 0 (evict immediately) by the system.
// +optional
TolerationSeconds *int64
} }
// A toleration operator is the set of operators that can be used in a toleration. // A toleration operator is the set of operators that can be used in a toleration.

View File

@ -2002,8 +2002,12 @@ type Taint struct {
Value string `json:"value,omitempty" protobuf:"bytes,2,opt,name=value"` Value string `json:"value,omitempty" protobuf:"bytes,2,opt,name=value"`
// Required. The effect of the taint on pods // Required. The effect of the taint on pods
// that do not tolerate the taint. // that do not tolerate the taint.
// Valid effects are NoSchedule and PreferNoSchedule. // Valid effects are NoSchedule, PreferNoSchedule and NoExecute.
Effect TaintEffect `json:"effect" protobuf:"bytes,3,opt,name=effect,casttype=TaintEffect"` Effect TaintEffect `json:"effect" protobuf:"bytes,3,opt,name=effect,casttype=TaintEffect"`
// TimeAdded represents the time at which the taint was added.
// It is only written for NoExecute taints.
// +optional
TimeAdded metav1.Time `json:"timeAdded,omitempty" protobuf:"bytes,4,opt,name=timeAdded"`
} }
type TaintEffect string type TaintEffect string
@ -2019,26 +2023,23 @@ const (
// onto the node entirely. Enforced by the scheduler. // onto the node entirely. Enforced by the scheduler.
TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule" TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule"
// NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. // NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented.
// Do not allow new pods to schedule onto the node unless they tolerate the taint, // Like TaintEffectNoSchedule, but additionally do not allow pods submitted to
// do not allow pods to start on Kubelet unless they tolerate the taint, // Kubelet without going through the scheduler to start.
// but allow all already-running pods to continue running. // Enforced by Kubelet and the scheduler.
// Enforced by the scheduler and Kubelet.
// TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit" // TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit"
// NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. // Evict any already-running pods that do not tolerate the taint.
// Do not allow new pods to schedule onto the node unless they tolerate the taint, // Currently enforced by NodeController.
// do not allow pods to start on Kubelet unless they tolerate the taint, TaintEffectNoExecute TaintEffect = "NoExecute"
// and evict any already-running pods that do not tolerate the taint.
// Enforced by the scheduler and Kubelet.
// TaintEffectNoScheduleNoAdmitNoExecute = "NoScheduleNoAdmitNoExecute"
) )
// The pod this Toleration is attached to tolerates any taint that matches // The pod this Toleration is attached to tolerates any taint that matches
// the triple <key,value,effect> using the matching operator <operator>. // the triple <key,value,effect> using the matching operator <operator>.
type Toleration struct { type Toleration struct {
// Required. Key is the taint key that the toleration applies to. // Key is the taint key that the toleration applies to. Empty means match all taint keys.
// If the key is empty, operator must be Exists; this combination means to match all values and all keys.
// +optional // +optional
Key string `json:"key,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,1,opt,name=key"` Key string `json:"key,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,1,opt,name=key"`
// operator represents a key's relationship to the value. // Operator represents a key's relationship to the value.
// Valid operators are Exists and Equal. Defaults to Equal. // Valid operators are Exists and Equal. Defaults to Equal.
// Exists is equivalent to wildcard for value, so that a pod can // Exists is equivalent to wildcard for value, so that a pod can
// tolerate all taints of a particular category. // tolerate all taints of a particular category.
@ -2049,11 +2050,15 @@ type Toleration struct {
// +optional // +optional
Value string `json:"value,omitempty" protobuf:"bytes,3,opt,name=value"` Value string `json:"value,omitempty" protobuf:"bytes,3,opt,name=value"`
// Effect indicates the taint effect to match. Empty means match all taint effects. // Effect indicates the taint effect to match. Empty means match all taint effects.
// When specified, allowed values are NoSchedule and PreferNoSchedule. // When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
// +optional // +optional
Effect TaintEffect `json:"effect,omitempty" protobuf:"bytes,4,opt,name=effect,casttype=TaintEffect"` Effect TaintEffect `json:"effect,omitempty" protobuf:"bytes,4,opt,name=effect,casttype=TaintEffect"`
// TODO: For forgiveness (#1574), we'd eventually add at least a grace period // TolerationSeconds represents the period of time the toleration (which must be
// here, and possibly an occurrence threshold and period. // of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
// it is not set, which means tolerate the taint forever (do not evict). Zero and
// negative values will be treated as 0 (evict immediately) by the system.
// +optional
TolerationSeconds *int64 `json:"tolerationSeconds,omitempty" protobuf:"varint,5,opt,name=tolerationSeconds"`
} }
// A toleration operator is the set of operators that can be used in a toleration. // A toleration operator is the set of operators that can be used in a toleration.

View File

@ -1717,16 +1717,16 @@ func validateTaintEffect(effect *api.TaintEffect, allowEmpty bool, fldPath *fiel
allErrors := field.ErrorList{} allErrors := field.ErrorList{}
switch *effect { switch *effect {
// TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit, TaintEffectNoScheduleNoAdmitNoExecute. // TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit.
case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule: case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule, api.TaintEffectNoExecute:
// case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule, api.TaintEffectNoScheduleNoAdmit, api.TaintEffectNoScheduleNoAdmitNoExecute: // case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule, api.TaintEffectNoScheduleNoAdmit, api.TaintEffectNoExecute:
default: default:
validValues := []string{ validValues := []string{
string(api.TaintEffectNoSchedule), string(api.TaintEffectNoSchedule),
string(api.TaintEffectPreferNoSchedule), string(api.TaintEffectPreferNoSchedule),
// TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit, TaintEffectNoScheduleNoAdmitNoExecute. string(api.TaintEffectNoExecute),
// TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit.
// string(api.TaintEffectNoScheduleNoAdmit), // string(api.TaintEffectNoScheduleNoAdmit),
// string(api.TaintEffectNoScheduleNoAdmitNoExecute),
} }
allErrors = append(allErrors, field.NotSupported(fldPath, effect, validValues)) allErrors = append(allErrors, field.NotSupported(fldPath, effect, validValues))
} }
@ -1739,10 +1739,24 @@ func validateTolerations(tolerations []api.Toleration, fldPath *field.Path) fiel
for i, toleration := range tolerations { for i, toleration := range tolerations {
idxPath := fldPath.Index(i) idxPath := fldPath.Index(i)
// validate the toleration key // validate the toleration key
allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...) if len(toleration.Key) > 0 {
allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...)
}
// empty toleration key with Exists operator and empty value means match all taints
if len(toleration.Key) == 0 && toleration.Operator != api.TolerationOpExists {
allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Operator,
"operator must be Exists when `key` is empty, which means \"match all values and all keys\""))
}
if toleration.TolerationSeconds != nil && toleration.Effect != api.TaintEffectNoExecute {
allErrors = append(allErrors, field.Invalid(idxPath.Child("effect"), toleration.Effect,
"effect must be 'NoExecute' when `tolerationSeconds` is set"))
}
// validate toleration operator and value // validate toleration operator and value
switch toleration.Operator { switch toleration.Operator {
// empty operator means Equal
case api.TolerationOpEqual, "": case api.TolerationOpEqual, "":
if errs := validation.IsValidLabelValue(toleration.Value); len(errs) != 0 { if errs := validation.IsValidLabelValue(toleration.Value); len(errs) != 0 {
allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Value, strings.Join(errs, ";"))) allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Value, strings.Join(errs, ";")))
@ -1756,7 +1770,7 @@ func validateTolerations(tolerations []api.Toleration, fldPath *field.Path) fiel
allErrors = append(allErrors, field.NotSupported(idxPath.Child("operator"), toleration.Operator, validValues)) allErrors = append(allErrors, field.NotSupported(idxPath.Child("operator"), toleration.Operator, validValues))
} }
// validate toleration effect // validate toleration effect, empty toleration effect means match all taint effects
if len(toleration.Effect) > 0 { if len(toleration.Effect) > 0 {
allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...) allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...)
} }

View File

@ -3378,6 +3378,40 @@ func TestValidatePod(t *testing.T) {
}, },
}), }),
}, },
{ // populate forgiveness tolerations with exists operator in annotations.
ObjectMeta: metav1.ObjectMeta{
Name: "123",
Namespace: "ns",
Annotations: map[string]string{
api.TolerationsAnnotationKey: `
[{
"key": "foo",
"operator": "Exists",
"value": "",
"effect": "NoExecute",
"tolerationSeconds": 60
}]`,
},
},
Spec: validPodSpec(nil),
},
{ // populate forgiveness tolerations with equal operator in annotations.
ObjectMeta: metav1.ObjectMeta{
Name: "123",
Namespace: "ns",
Annotations: map[string]string{
api.TolerationsAnnotationKey: `
[{
"key": "foo",
"operator": "Equal",
"value": "bar",
"effect": "NoExecute",
"tolerationSeconds": 60
}]`,
},
},
Spec: validPodSpec(nil),
},
{ // populate tolerations equal operator in annotations. { // populate tolerations equal operator in annotations.
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "123", Name: "123",
@ -3409,7 +3443,21 @@ func TestValidatePod(t *testing.T) {
}, },
Spec: validPodSpec(nil), Spec: validPodSpec(nil),
}, },
{ // empty operator is ok for toleration { // empty key with Exists operator is OK for toleration, empty toleration key means match all taint keys.
ObjectMeta: metav1.ObjectMeta{
Name: "123",
Namespace: "ns",
Annotations: map[string]string{
api.TolerationsAnnotationKey: `
[{
"operator": "Exists",
"effect": "NoSchedule"
}]`,
},
},
Spec: validPodSpec(nil),
},
{ // empty operator is OK for toleration, defaults to Equal.
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "123", Name: "123",
Namespace: "ns", Namespace: "ns",
@ -3424,7 +3472,7 @@ func TestValidatePod(t *testing.T) {
}, },
Spec: validPodSpec(nil), Spec: validPodSpec(nil),
}, },
{ // empty efffect is ok for toleration { // empty effect is OK for toleration, empty toleration effect means match all taint effects.
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "123", Name: "123",
Namespace: "ns", Namespace: "ns",
@ -3439,6 +3487,22 @@ func TestValidatePod(t *testing.T) {
}, },
Spec: validPodSpec(nil), Spec: validPodSpec(nil),
}, },
{ // negative tolerationSeconds is OK for toleration.
ObjectMeta: metav1.ObjectMeta{
Name: "pod-forgiveness-invalid",
Namespace: "ns",
Annotations: map[string]string{
api.TolerationsAnnotationKey: `
[{
"key": "node.alpha.kubernetes.io/notReady",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": -2
}]`,
},
},
Spec: validPodSpec(nil),
},
{ // docker default seccomp profile { // docker default seccomp profile
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "123", Name: "123",
@ -3898,6 +3962,38 @@ func TestValidatePod(t *testing.T) {
}, },
Spec: validPodSpec(nil), Spec: validPodSpec(nil),
}, },
"operator must be 'Exists' when `key` is empty": {
ObjectMeta: metav1.ObjectMeta{
Name: "123",
Namespace: "ns",
Annotations: map[string]string{
api.TolerationsAnnotationKey: `
[{
"operator": "Equal",
"value": "bar",
"effect": "NoSchedule"
}]`,
},
},
Spec: validPodSpec(nil),
},
"effect must be 'NoExecute' when `TolerationSeconds` is set": {
ObjectMeta: metav1.ObjectMeta{
Name: "pod-forgiveness-invalid",
Namespace: "ns",
Annotations: map[string]string{
api.TolerationsAnnotationKey: `
[{
"key": "node.alpha.kubernetes.io/notReady",
"operator": "Exists",
"effect": "NoSchedule",
"tolerationSeconds": 20
}]`,
},
},
Spec: validPodSpec(nil),
},
"must be a valid pod seccomp profile": { "must be a valid pod seccomp profile": {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "123", Name: "123",
@ -5927,7 +6023,7 @@ func TestValidateNode(t *testing.T) {
ExternalID: "external", ExternalID: "external",
}, },
}, },
"invalide-taint-effect": { "invalid-taint-effect": {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "dedicated-node3", Name: "dedicated-node3",
// Add a taint with an empty effect to a node // Add a taint with an empty effect to a node
@ -5936,7 +6032,7 @@ func TestValidateNode(t *testing.T) {
[{ [{
"key": "dedicated", "key": "dedicated",
"value": "special-user-3", "value": "special-user-3",
"effect": "NoExecute" "effect": "NoScheduleNoAdmit"
}]`, }]`,
}, },
}, },

View File

@ -33,6 +33,17 @@ const (
// of fluentd running on a node, kubelet need to mark node on which // of fluentd running on a node, kubelet need to mark node on which
// fluentd in not running as a manifest pod with LabelFluentdDsReady. // fluentd in not running as a manifest pod with LabelFluentdDsReady.
LabelFluentdDsReady = "alpha.kubernetes.io/fluentd-ds-ready" LabelFluentdDsReady = "alpha.kubernetes.io/fluentd-ds-ready"
// When the --use-taint-based-evictions flag is enabled,
// TaintNodeNotReady would be automatically added by node controller
// when node is not ready, and removed when node becomes ready.
TaintNodeNotReady = "node.alpha.kubernetes.io/notReady"
// When the --use-taint-based-evictions flag is enabled,
// TaintNodeUnreachable would be automatically added by node controller
// when node becomes unreachable (corresponding to NodeReady status ConditionUnknown)
// and removed when node becomes reachable (NodeReady status ConditionTrue).
TaintNodeUnreachable = "node.alpha.kubernetes.io/unreachable"
) )
// Role labels are applied to Nodes to mark their purpose. In particular, we // Role labels are applied to Nodes to mark their purpose. In particular, we