Merge pull request #24134 from Huawei-PaaS/taints-tolerations
Implement taints and tolerations
This commit is contained in:
@@ -175,6 +175,8 @@ func init() {
|
||||
DeepCopy_api_ServiceSpec,
|
||||
DeepCopy_api_ServiceStatus,
|
||||
DeepCopy_api_TCPSocketAction,
|
||||
DeepCopy_api_Taint,
|
||||
DeepCopy_api_Toleration,
|
||||
DeepCopy_api_Volume,
|
||||
DeepCopy_api_VolumeMount,
|
||||
DeepCopy_api_VolumeSource,
|
||||
@@ -2967,6 +2969,21 @@ func DeepCopy_api_TCPSocketAction(in TCPSocketAction, out *TCPSocketAction, c *c
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Taint(in Taint, out *Taint, c *conversion.Cloner) error {
|
||||
out.Key = in.Key
|
||||
out.Value = in.Value
|
||||
out.Effect = in.Effect
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Toleration(in Toleration, out *Toleration, c *conversion.Cloner) error {
|
||||
out.Key = in.Key
|
||||
out.Operator = in.Operator
|
||||
out.Value = in.Value
|
||||
out.Effect = in.Effect
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Volume(in Volume, out *Volume, c *conversion.Cloner) error {
|
||||
out.Name = in.Name
|
||||
if err := DeepCopy_api_VolumeSource(in.VolumeSource, &out.VolumeSource, c); err != nil {
|
||||
|
||||
@@ -411,9 +411,19 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
|
||||
return selector, nil
|
||||
}
|
||||
|
||||
// AffinityAnnotationKey represents the key of affinity data (json serialized)
|
||||
// in the Annotations of a Pod.
|
||||
const AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
|
||||
const (
|
||||
// AffinityAnnotationKey represents the key of affinity data (json serialized)
|
||||
// in the Annotations of a Pod.
|
||||
AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
|
||||
|
||||
// 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"
|
||||
)
|
||||
|
||||
// GetAffinityFromPod gets the json serialized affinity data from Pod.Annotations
|
||||
// and converts it to the Affinity type in api.
|
||||
@@ -427,3 +437,61 @@ func GetAffinityFromPodAnnotations(annotations map[string]string) (Affinity, err
|
||||
}
|
||||
return affinity, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// TolerationToleratesTaint checks if the toleration tolerates the taint.
|
||||
func TolerationToleratesTaint(toleration Toleration, taint Taint) bool {
|
||||
if len(toleration.Effect) != 0 && toleration.Effect != taint.Effect {
|
||||
return false
|
||||
}
|
||||
|
||||
if toleration.Key != taint.Key {
|
||||
return false
|
||||
}
|
||||
// TODO: Use proper defaulting when Toleration becomes a field of PodSpec
|
||||
if (len(toleration.Operator) == 0 || toleration.Operator == TolerationOpEqual) && toleration.Value == taint.Value {
|
||||
return true
|
||||
}
|
||||
if toleration.Operator == TolerationOpExists {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
// TaintToleratedByTolerations checks if taint is tolerated by any of the tolerations.
|
||||
func TaintToleratedByTolerations(taint Taint, tolerations []Toleration) bool {
|
||||
tolerated := false
|
||||
for _, toleration := range tolerations {
|
||||
if TolerationToleratesTaint(toleration, taint) {
|
||||
tolerated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return tolerated
|
||||
}
|
||||
|
||||
@@ -24521,6 +24521,592 @@ func (x *PreferredSchedulingTerm) codecDecodeSelfFromArray(l int, d *codec1978.D
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
||||
func (x *Taint) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
if x == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [3]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[1] = x.Value != ""
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(3)
|
||||
} else {
|
||||
yynn2 = 2
|
||||
for _, b := range yyq2 {
|
||||
if b {
|
||||
yynn2++
|
||||
}
|
||||
}
|
||||
r.EncodeMapStart(yynn2)
|
||||
yynn2 = 0
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
yym4 := z.EncBinary()
|
||||
_ = yym4
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("key"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym5 := z.EncBinary()
|
||||
_ = yym5
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[1] {
|
||||
yym7 := z.EncBinary()
|
||||
_ = yym7
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[1] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("value"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym8 := z.EncBinary()
|
||||
_ = yym8
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("effect"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Taint) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
yyct2 := r.ContainerType()
|
||||
if yyct2 == codecSelferValueTypeMap1234 {
|
||||
yyl2 := r.ReadMapStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromMap(yyl2, d)
|
||||
}
|
||||
} else if yyct2 == codecSelferValueTypeArray1234 {
|
||||
yyl2 := r.ReadArrayStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromArray(yyl2, d)
|
||||
}
|
||||
} else {
|
||||
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Taint) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
|
||||
_ = yys3Slc
|
||||
var yyhl3 bool = l >= 0
|
||||
for yyj3 := 0; ; yyj3++ {
|
||||
if yyhl3 {
|
||||
if yyj3 >= l {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if r.CheckBreak() {
|
||||
break
|
||||
}
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerMapKey1234)
|
||||
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
|
||||
yys3 := string(yys3Slc)
|
||||
z.DecSendContainerState(codecSelfer_containerMapValue1234)
|
||||
switch yys3 {
|
||||
case "key":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
case "value":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
case "effect":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
} // end for yyj3
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
|
||||
func (x *Taint) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj7 int
|
||||
var yyb7 bool
|
||||
var yyhl7 bool = l >= 0
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj7-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
||||
func (x TaintEffect) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x))
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TaintEffect) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
*((*string)(x)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Toleration) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
if x == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [4]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[0] = x.Key != ""
|
||||
yyq2[1] = x.Operator != ""
|
||||
yyq2[2] = x.Value != ""
|
||||
yyq2[3] = x.Effect != ""
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(4)
|
||||
} else {
|
||||
yynn2 = 0
|
||||
for _, b := range yyq2 {
|
||||
if b {
|
||||
yynn2++
|
||||
}
|
||||
}
|
||||
r.EncodeMapStart(yynn2)
|
||||
yynn2 = 0
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[0] {
|
||||
yym4 := z.EncBinary()
|
||||
_ = yym4
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[0] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("key"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym5 := z.EncBinary()
|
||||
_ = yym5
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[1] {
|
||||
x.Operator.CodecEncodeSelf(e)
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[1] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("operator"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.Operator.CodecEncodeSelf(e)
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[2] {
|
||||
yym10 := z.EncBinary()
|
||||
_ = yym10
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[2] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("value"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym11 := z.EncBinary()
|
||||
_ = yym11
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[3] {
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[3] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("effect"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Toleration) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
yyct2 := r.ContainerType()
|
||||
if yyct2 == codecSelferValueTypeMap1234 {
|
||||
yyl2 := r.ReadMapStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromMap(yyl2, d)
|
||||
}
|
||||
} else if yyct2 == codecSelferValueTypeArray1234 {
|
||||
yyl2 := r.ReadArrayStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromArray(yyl2, d)
|
||||
}
|
||||
} else {
|
||||
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Toleration) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
|
||||
_ = yys3Slc
|
||||
var yyhl3 bool = l >= 0
|
||||
for yyj3 := 0; ; yyj3++ {
|
||||
if yyhl3 {
|
||||
if yyj3 >= l {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if r.CheckBreak() {
|
||||
break
|
||||
}
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerMapKey1234)
|
||||
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
|
||||
yys3 := string(yys3Slc)
|
||||
z.DecSendContainerState(codecSelfer_containerMapValue1234)
|
||||
switch yys3 {
|
||||
case "key":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
case "operator":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Operator = ""
|
||||
} else {
|
||||
x.Operator = TolerationOperator(r.DecodeString())
|
||||
}
|
||||
case "value":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
case "effect":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
} // end for yyj3
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
|
||||
func (x *Toleration) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj8 int
|
||||
var yyb8 bool
|
||||
var yyhl8 bool = l >= 0
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Operator = ""
|
||||
} else {
|
||||
x.Operator = TolerationOperator(r.DecodeString())
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj8-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
||||
func (x TolerationOperator) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x))
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TolerationOperator) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
*((*string)(x)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
|
||||
@@ -1308,6 +1308,73 @@ type PreferredSchedulingTerm struct {
|
||||
Preference NodeSelectorTerm `json:"preference"`
|
||||
}
|
||||
|
||||
// The node this Taint is attached to has the effect "effect" on
|
||||
// any pod that that does not tolerate the Taint.
|
||||
type Taint struct {
|
||||
// Required. The taint key to be applied to a node.
|
||||
Key string `json:"key" patchStrategy:"merge" patchMergeKey:"key"`
|
||||
// Required. The taint value corresponding to the taint key.
|
||||
Value string `json:"value,omitempty"`
|
||||
// Required. The effect of the taint on pods
|
||||
// that do not tolerate the taint.
|
||||
// Valid effects are NoSchedule and PreferNoSchedule.
|
||||
Effect TaintEffect `json:"effect"`
|
||||
}
|
||||
|
||||
type TaintEffect string
|
||||
|
||||
const (
|
||||
// Do not allow new pods to schedule onto the node unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
// Enforced by the scheduler.
|
||||
TaintEffectNoSchedule TaintEffect = "NoSchedule"
|
||||
// Like TaintEffectNoSchedule, but the scheduler tries not to schedule
|
||||
// new pods onto the node, rather than prohibiting new pods from scheduling
|
||||
// onto the node entirely. Enforced by the scheduler.
|
||||
TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule"
|
||||
// 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,
|
||||
// do not allow pods to start on Kubelet unless they tolerate the taint,
|
||||
// but allow all already-running pods to continue running.
|
||||
// Enforced by the scheduler and Kubelet.
|
||||
// TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit"
|
||||
// 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,
|
||||
// do not allow pods to start on Kubelet unless they tolerate the taint,
|
||||
// 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 triple <key,value,effect> using the matching operator <operator>.
|
||||
type Toleration struct {
|
||||
// Required. Key is the taint key that the toleration applies to.
|
||||
Key string `json:"key,omitempty" patchStrategy:"merge" patchMergeKey:"key"`
|
||||
// operator represents a key's relationship to the value.
|
||||
// Valid operators are Exists and Equal. Defaults to Equal.
|
||||
// Exists is equivalent to wildcard for value, so that a pod can
|
||||
// tolerate all taints of a particular category.
|
||||
Operator TolerationOperator `json:"operator,omitempty"`
|
||||
// Value is the taint value the toleration matches to.
|
||||
// If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||
Value string `json:"value,omitempty"`
|
||||
// Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||
// When specified, allowed values are NoSchedule and PreferNoSchedule.
|
||||
Effect TaintEffect `json:"effect,omitempty"`
|
||||
// TODO: For forgiveness (#1574), we'd eventually add at least a grace period
|
||||
// here, and possibly an occurrence threshold and period.
|
||||
}
|
||||
|
||||
// A toleration operator is the set of operators that can be used in a toleration.
|
||||
type TolerationOperator string
|
||||
|
||||
const (
|
||||
TolerationOpExists TolerationOperator = "Exists"
|
||||
TolerationOpEqual TolerationOperator = "Equal"
|
||||
)
|
||||
|
||||
// PodSpec is a description of a pod
|
||||
type PodSpec struct {
|
||||
Volumes []Volume `json:"volumes"`
|
||||
|
||||
@@ -311,6 +311,10 @@ func init() {
|
||||
Convert_api_ServiceStatus_To_v1_ServiceStatus,
|
||||
Convert_v1_TCPSocketAction_To_api_TCPSocketAction,
|
||||
Convert_api_TCPSocketAction_To_v1_TCPSocketAction,
|
||||
Convert_v1_Taint_To_api_Taint,
|
||||
Convert_api_Taint_To_v1_Taint,
|
||||
Convert_v1_Toleration_To_api_Toleration,
|
||||
Convert_api_Toleration_To_v1_Toleration,
|
||||
Convert_v1_Volume_To_api_Volume,
|
||||
Convert_api_Volume_To_v1_Volume,
|
||||
Convert_v1_VolumeMount_To_api_VolumeMount,
|
||||
@@ -6548,6 +6552,52 @@ func Convert_api_TCPSocketAction_To_v1_TCPSocketAction(in *api.TCPSocketAction,
|
||||
return autoConvert_api_TCPSocketAction_To_v1_TCPSocketAction(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Taint_To_api_Taint(in *Taint, out *api.Taint, s conversion.Scope) error {
|
||||
out.Key = in.Key
|
||||
out.Value = in.Value
|
||||
out.Effect = api.TaintEffect(in.Effect)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_Taint_To_api_Taint(in *Taint, out *api.Taint, s conversion.Scope) error {
|
||||
return autoConvert_v1_Taint_To_api_Taint(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_Taint_To_v1_Taint(in *api.Taint, out *Taint, s conversion.Scope) error {
|
||||
out.Key = in.Key
|
||||
out.Value = in.Value
|
||||
out.Effect = TaintEffect(in.Effect)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_Taint_To_v1_Taint(in *api.Taint, out *Taint, s conversion.Scope) error {
|
||||
return autoConvert_api_Taint_To_v1_Taint(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Toleration_To_api_Toleration(in *Toleration, out *api.Toleration, s conversion.Scope) error {
|
||||
out.Key = in.Key
|
||||
out.Operator = api.TolerationOperator(in.Operator)
|
||||
out.Value = in.Value
|
||||
out.Effect = api.TaintEffect(in.Effect)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_Toleration_To_api_Toleration(in *Toleration, out *api.Toleration, s conversion.Scope) error {
|
||||
return autoConvert_v1_Toleration_To_api_Toleration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_Toleration_To_v1_Toleration(in *api.Toleration, out *Toleration, s conversion.Scope) error {
|
||||
out.Key = in.Key
|
||||
out.Operator = TolerationOperator(in.Operator)
|
||||
out.Value = in.Value
|
||||
out.Effect = TaintEffect(in.Effect)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_Toleration_To_v1_Toleration(in *api.Toleration, out *Toleration, s conversion.Scope) error {
|
||||
return autoConvert_api_Toleration_To_v1_Toleration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Volume_To_api_Volume(in *Volume, out *api.Volume, s conversion.Scope) error {
|
||||
SetDefaults_Volume(in)
|
||||
out.Name = in.Name
|
||||
|
||||
@@ -172,6 +172,8 @@ func init() {
|
||||
DeepCopy_v1_ServiceSpec,
|
||||
DeepCopy_v1_ServiceStatus,
|
||||
DeepCopy_v1_TCPSocketAction,
|
||||
DeepCopy_v1_Taint,
|
||||
DeepCopy_v1_Toleration,
|
||||
DeepCopy_v1_Volume,
|
||||
DeepCopy_v1_VolumeMount,
|
||||
DeepCopy_v1_VolumeSource,
|
||||
@@ -2928,6 +2930,21 @@ func DeepCopy_v1_TCPSocketAction(in TCPSocketAction, out *TCPSocketAction, c *co
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_v1_Taint(in Taint, out *Taint, c *conversion.Cloner) error {
|
||||
out.Key = in.Key
|
||||
out.Value = in.Value
|
||||
out.Effect = in.Effect
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_v1_Toleration(in Toleration, out *Toleration, c *conversion.Cloner) error {
|
||||
out.Key = in.Key
|
||||
out.Operator = in.Operator
|
||||
out.Value = in.Value
|
||||
out.Effect = in.Effect
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_v1_Volume(in Volume, out *Volume, c *conversion.Cloner) error {
|
||||
out.Name = in.Name
|
||||
if err := DeepCopy_v1_VolumeSource(in.VolumeSource, &out.VolumeSource, c); err != nil {
|
||||
|
||||
@@ -165,6 +165,8 @@ limitations under the License.
|
||||
ServiceSpec
|
||||
ServiceStatus
|
||||
TCPSocketAction
|
||||
Taint
|
||||
Toleration
|
||||
Volume
|
||||
VolumeMount
|
||||
VolumeSource
|
||||
@@ -749,6 +751,14 @@ func (m *TCPSocketAction) Reset() { *m = TCPSocketAction{} }
|
||||
func (m *TCPSocketAction) String() string { return proto.CompactTextString(m) }
|
||||
func (*TCPSocketAction) ProtoMessage() {}
|
||||
|
||||
func (m *Taint) Reset() { *m = Taint{} }
|
||||
func (m *Taint) String() string { return proto.CompactTextString(m) }
|
||||
func (*Taint) ProtoMessage() {}
|
||||
|
||||
func (m *Toleration) Reset() { *m = Toleration{} }
|
||||
func (m *Toleration) String() string { return proto.CompactTextString(m) }
|
||||
func (*Toleration) ProtoMessage() {}
|
||||
|
||||
func (m *Volume) Reset() { *m = Volume{} }
|
||||
func (m *Volume) String() string { return proto.CompactTextString(m) }
|
||||
func (*Volume) ProtoMessage() {}
|
||||
@@ -906,6 +916,8 @@ func init() {
|
||||
proto.RegisterType((*ServiceSpec)(nil), "k8s.io.kubernetes.pkg.api.v1.ServiceSpec")
|
||||
proto.RegisterType((*ServiceStatus)(nil), "k8s.io.kubernetes.pkg.api.v1.ServiceStatus")
|
||||
proto.RegisterType((*TCPSocketAction)(nil), "k8s.io.kubernetes.pkg.api.v1.TCPSocketAction")
|
||||
proto.RegisterType((*Taint)(nil), "k8s.io.kubernetes.pkg.api.v1.Taint")
|
||||
proto.RegisterType((*Toleration)(nil), "k8s.io.kubernetes.pkg.api.v1.Toleration")
|
||||
proto.RegisterType((*Volume)(nil), "k8s.io.kubernetes.pkg.api.v1.Volume")
|
||||
proto.RegisterType((*VolumeMount)(nil), "k8s.io.kubernetes.pkg.api.v1.VolumeMount")
|
||||
proto.RegisterType((*VolumeSource)(nil), "k8s.io.kubernetes.pkg.api.v1.VolumeSource")
|
||||
@@ -7111,6 +7123,70 @@ func (m *TCPSocketAction) MarshalTo(data []byte) (int, error) {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Taint) Marshal() (data []byte, err error) {
|
||||
size := m.Size()
|
||||
data = make([]byte, size)
|
||||
n, err := m.MarshalTo(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[:n], nil
|
||||
}
|
||||
|
||||
func (m *Taint) MarshalTo(data []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
data[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Key)))
|
||||
i += copy(data[i:], m.Key)
|
||||
data[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Value)))
|
||||
i += copy(data[i:], m.Value)
|
||||
data[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Effect)))
|
||||
i += copy(data[i:], m.Effect)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Toleration) Marshal() (data []byte, err error) {
|
||||
size := m.Size()
|
||||
data = make([]byte, size)
|
||||
n, err := m.MarshalTo(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[:n], nil
|
||||
}
|
||||
|
||||
func (m *Toleration) MarshalTo(data []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
data[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Key)))
|
||||
i += copy(data[i:], m.Key)
|
||||
data[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Operator)))
|
||||
i += copy(data[i:], m.Operator)
|
||||
data[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Value)))
|
||||
i += copy(data[i:], m.Value)
|
||||
data[i] = 0x22
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.Effect)))
|
||||
i += copy(data[i:], m.Effect)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Volume) Marshal() (data []byte, err error) {
|
||||
size := m.Size()
|
||||
data = make([]byte, size)
|
||||
@@ -9724,6 +9800,32 @@ func (m *TCPSocketAction) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Taint) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Key)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = len(m.Value)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = len(m.Effect)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Toleration) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Key)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = len(m.Operator)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = len(m.Value)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = len(m.Effect)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Volume) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
@@ -32142,6 +32244,309 @@ func (m *TCPSocketAction) Unmarshal(data []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Taint) Unmarshal(data []byte) error {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Taint: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Taint: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Key = string(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Value = string(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Effect", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Effect = TaintEffect(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(data[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Toleration) Unmarshal(data []byte) error {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Toleration: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Toleration: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Key = string(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Operator", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Operator = TolerationOperator(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Value = string(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Effect", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Effect = TaintEffect(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(data[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Volume) Unmarshal(data []byte) error {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
|
||||
@@ -2686,6 +2686,42 @@ message TCPSocketAction {
|
||||
optional k8s.io.kubernetes.pkg.util.intstr.IntOrString port = 1;
|
||||
}
|
||||
|
||||
// The node this Taint is attached to has the effect "effect" on
|
||||
// any pod that that does not tolerate the Taint.
|
||||
message Taint {
|
||||
// Required. The taint key to be applied to a node.
|
||||
optional string key = 1;
|
||||
|
||||
// Required. The taint value corresponding to the taint key.
|
||||
optional string value = 2;
|
||||
|
||||
// Required. The effect of the taint on pods
|
||||
// that do not tolerate the taint.
|
||||
// Valid effects are NoSchedule and PreferNoSchedule.
|
||||
optional string effect = 3;
|
||||
}
|
||||
|
||||
// The pod this Toleration is attached to tolerates any taint that matches
|
||||
// the triple <key,value,effect> using the matching operator <operator>.
|
||||
message Toleration {
|
||||
// Required. Key is the taint key that the toleration applies to.
|
||||
optional string key = 1;
|
||||
|
||||
// operator represents a key's relationship to the value.
|
||||
// Valid operators are Exists and Equal. Defaults to Equal.
|
||||
// Exists is equivalent to wildcard for value, so that a pod can
|
||||
// tolerate all taints of a particular category.
|
||||
optional string operator = 2;
|
||||
|
||||
// Value is the taint value the toleration matches to.
|
||||
// If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||
optional string value = 3;
|
||||
|
||||
// Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||
// When specified, allowed values are NoSchedule and PreferNoSchedule.
|
||||
optional string effect = 4;
|
||||
}
|
||||
|
||||
// Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||
message Volume {
|
||||
// Volume's name.
|
||||
|
||||
@@ -23801,6 +23801,592 @@ func (x *PreferredSchedulingTerm) codecDecodeSelfFromArray(l int, d *codec1978.D
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
||||
func (x *Taint) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
if x == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [3]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[1] = x.Value != ""
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(3)
|
||||
} else {
|
||||
yynn2 = 2
|
||||
for _, b := range yyq2 {
|
||||
if b {
|
||||
yynn2++
|
||||
}
|
||||
}
|
||||
r.EncodeMapStart(yynn2)
|
||||
yynn2 = 0
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
yym4 := z.EncBinary()
|
||||
_ = yym4
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("key"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym5 := z.EncBinary()
|
||||
_ = yym5
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[1] {
|
||||
yym7 := z.EncBinary()
|
||||
_ = yym7
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[1] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("value"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym8 := z.EncBinary()
|
||||
_ = yym8
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("effect"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Taint) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
yyct2 := r.ContainerType()
|
||||
if yyct2 == codecSelferValueTypeMap1234 {
|
||||
yyl2 := r.ReadMapStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromMap(yyl2, d)
|
||||
}
|
||||
} else if yyct2 == codecSelferValueTypeArray1234 {
|
||||
yyl2 := r.ReadArrayStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromArray(yyl2, d)
|
||||
}
|
||||
} else {
|
||||
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Taint) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
|
||||
_ = yys3Slc
|
||||
var yyhl3 bool = l >= 0
|
||||
for yyj3 := 0; ; yyj3++ {
|
||||
if yyhl3 {
|
||||
if yyj3 >= l {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if r.CheckBreak() {
|
||||
break
|
||||
}
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerMapKey1234)
|
||||
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
|
||||
yys3 := string(yys3Slc)
|
||||
z.DecSendContainerState(codecSelfer_containerMapValue1234)
|
||||
switch yys3 {
|
||||
case "key":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
case "value":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
case "effect":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
} // end for yyj3
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
|
||||
func (x *Taint) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj7 int
|
||||
var yyb7 bool
|
||||
var yyhl7 bool = l >= 0
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj7-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
||||
func (x TaintEffect) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x))
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TaintEffect) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
*((*string)(x)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Toleration) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
if x == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [4]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[0] = x.Key != ""
|
||||
yyq2[1] = x.Operator != ""
|
||||
yyq2[2] = x.Value != ""
|
||||
yyq2[3] = x.Effect != ""
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(4)
|
||||
} else {
|
||||
yynn2 = 0
|
||||
for _, b := range yyq2 {
|
||||
if b {
|
||||
yynn2++
|
||||
}
|
||||
}
|
||||
r.EncodeMapStart(yynn2)
|
||||
yynn2 = 0
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[0] {
|
||||
yym4 := z.EncBinary()
|
||||
_ = yym4
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[0] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("key"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym5 := z.EncBinary()
|
||||
_ = yym5
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Key))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[1] {
|
||||
x.Operator.CodecEncodeSelf(e)
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[1] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("operator"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.Operator.CodecEncodeSelf(e)
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[2] {
|
||||
yym10 := z.EncBinary()
|
||||
_ = yym10
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[2] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("value"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym11 := z.EncBinary()
|
||||
_ = yym11
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.Value))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[3] {
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[3] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("effect"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.Effect.CodecEncodeSelf(e)
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Toleration) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
yyct2 := r.ContainerType()
|
||||
if yyct2 == codecSelferValueTypeMap1234 {
|
||||
yyl2 := r.ReadMapStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromMap(yyl2, d)
|
||||
}
|
||||
} else if yyct2 == codecSelferValueTypeArray1234 {
|
||||
yyl2 := r.ReadArrayStart()
|
||||
if yyl2 == 0 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
x.codecDecodeSelfFromArray(yyl2, d)
|
||||
}
|
||||
} else {
|
||||
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Toleration) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
|
||||
_ = yys3Slc
|
||||
var yyhl3 bool = l >= 0
|
||||
for yyj3 := 0; ; yyj3++ {
|
||||
if yyhl3 {
|
||||
if yyj3 >= l {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if r.CheckBreak() {
|
||||
break
|
||||
}
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerMapKey1234)
|
||||
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
|
||||
yys3 := string(yys3Slc)
|
||||
z.DecSendContainerState(codecSelfer_containerMapValue1234)
|
||||
switch yys3 {
|
||||
case "key":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
case "operator":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Operator = ""
|
||||
} else {
|
||||
x.Operator = TolerationOperator(r.DecodeString())
|
||||
}
|
||||
case "value":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
case "effect":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
} // end for yyj3
|
||||
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
|
||||
}
|
||||
|
||||
func (x *Toleration) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj8 int
|
||||
var yyb8 bool
|
||||
var yyhl8 bool = l >= 0
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Key = ""
|
||||
} else {
|
||||
x.Key = string(r.DecodeString())
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Operator = ""
|
||||
} else {
|
||||
x.Operator = TolerationOperator(r.DecodeString())
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Value = ""
|
||||
} else {
|
||||
x.Value = string(r.DecodeString())
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Effect = ""
|
||||
} else {
|
||||
x.Effect = TaintEffect(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj8-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
||||
func (x TolerationOperator) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x))
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TolerationOperator) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
*((*string)(x)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
|
||||
@@ -1541,6 +1541,73 @@ type PreferredSchedulingTerm struct {
|
||||
Preference NodeSelectorTerm `json:"preference" protobuf:"bytes,2,opt,name=preference"`
|
||||
}
|
||||
|
||||
// The node this Taint is attached to has the effect "effect" on
|
||||
// any pod that that does not tolerate the Taint.
|
||||
type Taint struct {
|
||||
// Required. The taint key to be applied to a node.
|
||||
Key string `json:"key" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,1,opt,name=key"`
|
||||
// Required. The taint value corresponding to the taint key.
|
||||
Value string `json:"value,omitempty" protobuf:"bytes,2,opt,name=value"`
|
||||
// Required. The effect of the taint on pods
|
||||
// that do not tolerate the taint.
|
||||
// Valid effects are NoSchedule and PreferNoSchedule.
|
||||
Effect TaintEffect `json:"effect" protobuf:"bytes,3,opt,name=effect,casttype=TaintEffect"`
|
||||
}
|
||||
|
||||
type TaintEffect string
|
||||
|
||||
const (
|
||||
// Do not allow new pods to schedule onto the node unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
// Enforced by the scheduler.
|
||||
TaintEffectNoSchedule TaintEffect = "NoSchedule"
|
||||
// Like TaintEffectNoSchedule, but the scheduler tries not to schedule
|
||||
// new pods onto the node, rather than prohibiting new pods from scheduling
|
||||
// onto the node entirely. Enforced by the scheduler.
|
||||
TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule"
|
||||
// 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,
|
||||
// do not allow pods to start on Kubelet unless they tolerate the taint,
|
||||
// but allow all already-running pods to continue running.
|
||||
// Enforced by the scheduler and Kubelet.
|
||||
// TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit"
|
||||
// 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,
|
||||
// do not allow pods to start on Kubelet unless they tolerate the taint,
|
||||
// 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 triple <key,value,effect> using the matching operator <operator>.
|
||||
type Toleration struct {
|
||||
// Required. Key is the taint key that the toleration applies to.
|
||||
Key string `json:"key,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,1,opt,name=key"`
|
||||
// operator represents a key's relationship to the value.
|
||||
// Valid operators are Exists and Equal. Defaults to Equal.
|
||||
// Exists is equivalent to wildcard for value, so that a pod can
|
||||
// tolerate all taints of a particular category.
|
||||
Operator TolerationOperator `json:"operator,omitempty" protobuf:"bytes,2,opt,name=operator,casttype=TolerationOperator"`
|
||||
// Value is the taint value the toleration matches to.
|
||||
// If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||
Value string `json:"value,omitempty" protobuf:"bytes,3,opt,name=value"`
|
||||
// Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||
// When specified, allowed values are NoSchedule and PreferNoSchedule.
|
||||
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
|
||||
// here, and possibly an occurrence threshold and period.
|
||||
}
|
||||
|
||||
// A toleration operator is the set of operators that can be used in a toleration.
|
||||
type TolerationOperator string
|
||||
|
||||
const (
|
||||
TolerationOpExists TolerationOperator = "Exists"
|
||||
TolerationOpEqual TolerationOperator = "Equal"
|
||||
)
|
||||
|
||||
const (
|
||||
// This annotation key will be used to contain an array of v1 JSON encoded Containers
|
||||
// for init containers. The annotation will be placed into the internal type and cleared.
|
||||
|
||||
@@ -1616,6 +1616,29 @@ func (TCPSocketAction) SwaggerDoc() map[string]string {
|
||||
return map_TCPSocketAction
|
||||
}
|
||||
|
||||
var map_Taint = map[string]string{
|
||||
"": "The node this Taint is attached to has the effect \"effect\" on any pod that that does not tolerate the Taint.",
|
||||
"key": "Required. The taint key to be applied to a node.",
|
||||
"value": "Required. The taint value corresponding to the taint key.",
|
||||
"effect": "Required. The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule and PreferNoSchedule.",
|
||||
}
|
||||
|
||||
func (Taint) SwaggerDoc() map[string]string {
|
||||
return map_Taint
|
||||
}
|
||||
|
||||
var map_Toleration = map[string]string{
|
||||
"": "The pod this Toleration is attached to tolerates any taint that matches the triple <key,value,effect> using the matching operator <operator>.",
|
||||
"key": "Required. Key is the taint key that the toleration applies to.",
|
||||
"operator": "operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.",
|
||||
"value": "Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.",
|
||||
"effect": "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and PreferNoSchedule.",
|
||||
}
|
||||
|
||||
func (Toleration) SwaggerDoc() map[string]string {
|
||||
return map_Toleration
|
||||
}
|
||||
|
||||
var map_Volume = map[string]string{
|
||||
"": "Volume represents a named volume in a pod that may be accessed by any container in the pod.",
|
||||
"name": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names",
|
||||
|
||||
@@ -109,6 +109,10 @@ func ValidatePodSpecificAnnotations(annotations map[string]string, fldPath *fiel
|
||||
allErrs = append(allErrs, ValidateAffinityInPodAnnotations(annotations, fldPath)...)
|
||||
}
|
||||
|
||||
if annotations[api.TolerationsAnnotationKey] != "" {
|
||||
allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
|
||||
}
|
||||
|
||||
if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists && !validation.IsDNS1123Label(hostname) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodHostnameAnnotation, DNS1123LabelErrorMsg))
|
||||
}
|
||||
@@ -1462,6 +1466,60 @@ func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference, fldPa
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateTaintEffect(effect *api.TaintEffect, allowEmpty bool, fldPath *field.Path) field.ErrorList {
|
||||
if !allowEmpty && len(*effect) == 0 {
|
||||
return field.ErrorList{field.Required(fldPath, "")}
|
||||
}
|
||||
|
||||
allErrors := field.ErrorList{}
|
||||
switch *effect {
|
||||
// TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit, TaintEffectNoScheduleNoAdmitNoExecute.
|
||||
case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule:
|
||||
// case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule, api.TaintEffectNoScheduleNoAdmit, api.TaintEffectNoScheduleNoAdmitNoExecute:
|
||||
default:
|
||||
validValues := []string{
|
||||
string(api.TaintEffectNoSchedule),
|
||||
string(api.TaintEffectPreferNoSchedule),
|
||||
// TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit, TaintEffectNoScheduleNoAdmitNoExecute.
|
||||
// string(api.TaintEffectNoScheduleNoAdmit),
|
||||
// string(api.TaintEffectNoScheduleNoAdmitNoExecute),
|
||||
}
|
||||
allErrors = append(allErrors, field.NotSupported(fldPath, effect, validValues))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// validateTolerations tests if given tolerations have valid data.
|
||||
func validateTolerations(tolerations []api.Toleration, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
for i, toleration := range tolerations {
|
||||
idxPath := fldPath.Index(i)
|
||||
// validate the toleration key
|
||||
allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...)
|
||||
|
||||
// validate toleration operator and value
|
||||
switch toleration.Operator {
|
||||
case api.TolerationOpEqual, "":
|
||||
if errs := validation.IsValidLabelValue(toleration.Value); len(errs) != 0 {
|
||||
allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Value, strings.Join(errs, ";")))
|
||||
}
|
||||
case api.TolerationOpExists:
|
||||
if len(toleration.Value) > 0 {
|
||||
allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration, "value must be empty when `operator` is 'Exists'"))
|
||||
}
|
||||
default:
|
||||
validValues := []string{string(api.TolerationOpEqual), string(api.TolerationOpExists)}
|
||||
allErrors = append(allErrors, field.NotSupported(idxPath.Child("operator"), toleration.Operator, validValues))
|
||||
}
|
||||
|
||||
// validate toleration effect
|
||||
if len(toleration.Effect) > 0 {
|
||||
allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...)
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// ValidatePod tests if required fields in the pod are set.
|
||||
func ValidatePod(pod *api.Pod) field.ErrorList {
|
||||
fldPath := field.NewPath("metadata")
|
||||
@@ -1701,6 +1759,22 @@ func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *fi
|
||||
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{}
|
||||
|
||||
tolerations, err := api.GetTolerationsFromPodAnnotations(annotations)
|
||||
if 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
|
||||
}
|
||||
|
||||
// ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
|
||||
func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec, specPath, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
@@ -2113,9 +2187,51 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateTaints tests if given taints have valid data.
|
||||
func validateTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
for i, currTaint := range taints {
|
||||
idxPath := fldPath.Index(i)
|
||||
// validate the taint key
|
||||
allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(currTaint.Key, idxPath.Child("key"))...)
|
||||
// validate the taint value
|
||||
if errs := validation.IsValidLabelValue(currTaint.Value); len(errs) != 0 {
|
||||
allErrors = append(allErrors, field.Invalid(idxPath.Child("value"), currTaint.Value, strings.Join(errs, ";")))
|
||||
}
|
||||
// validate the taint effect
|
||||
allErrors = append(allErrors, validateTaintEffect(&currTaint.Effect, false, idxPath.Child("effect"))...)
|
||||
}
|
||||
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{}
|
||||
|
||||
taints, err := api.GetTaintsFromNodeAnnotations(annotations)
|
||||
if 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 {
|
||||
if annotations[api.TaintsAnnotationKey] != "" {
|
||||
return ValidateTaintsInNodeAnnotations(annotations, fldPath)
|
||||
}
|
||||
return field.ErrorList{}
|
||||
}
|
||||
|
||||
// ValidateNode tests if required fields in the node are set.
|
||||
func ValidateNode(node *api.Node) field.ErrorList {
|
||||
allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, field.NewPath("metadata"))
|
||||
fldPath := field.NewPath("metadata")
|
||||
allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, fldPath)
|
||||
allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
|
||||
|
||||
// Only validate spec. All status fields are optional and can be updated later.
|
||||
|
||||
@@ -2130,7 +2246,9 @@ func ValidateNode(node *api.Node) field.ErrorList {
|
||||
|
||||
// ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode.
|
||||
func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList {
|
||||
allErrs := ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, field.NewPath("metadata"))
|
||||
fldPath := field.NewPath("metadata")
|
||||
allErrs := ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, fldPath)
|
||||
allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
|
||||
|
||||
// TODO: Enable the code once we have better api object.status update model. Currently,
|
||||
// anyone can update node status.
|
||||
|
||||
@@ -1954,60 +1954,6 @@ func TestValidatePod(t *testing.T) {
|
||||
NodeName: "foobar",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, pod := range successCases {
|
||||
if errs := ValidatePod(&pod); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
errorCases := map[string]api.Pod{
|
||||
"bad name": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: "ns"},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
"bad namespace": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: ""},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
"bad spec": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{}},
|
||||
},
|
||||
},
|
||||
"bad label": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: "ns",
|
||||
Labels: map[string]string{
|
||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
if errs := ValidatePod(&v); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %q", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAffinity(t *testing.T) {
|
||||
successCases := []api.Pod{
|
||||
{ // Serialized affinity requirements in annotations.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
@@ -2160,6 +2106,83 @@ func TestValidateAffinity(t *testing.T) {
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
{ // populate tolerations equal operator in annotations.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "foo",
|
||||
"operator": "Equal",
|
||||
"value": "bar",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
{ // populate tolerations exists operator in annotations.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "foo",
|
||||
"operator": "Exists",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
{ // empty operator is ok for toleration
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "foo",
|
||||
"value": "bar",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
{ // empty efffect is ok for toleration
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "foo",
|
||||
"operator": "Equal",
|
||||
"value": "bar"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, pod := range successCases {
|
||||
if errs := ValidatePod(&pod); len(errs) != 0 {
|
||||
@@ -2168,6 +2191,42 @@ func TestValidateAffinity(t *testing.T) {
|
||||
}
|
||||
|
||||
errorCases := map[string]api.Pod{
|
||||
"bad name": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: "ns"},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
"bad namespace": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: ""},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
"bad spec": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{}},
|
||||
},
|
||||
},
|
||||
"bad label": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: "ns",
|
||||
Labels: map[string]string{
|
||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
"invalid json of node affinity in pod annotations": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
@@ -2476,6 +2535,66 @@ func TestValidateAffinity(t *testing.T) {
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
"invalid toleration key": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "nospecialchars^=@",
|
||||
"operator": "Equal",
|
||||
"value": "bar",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
"invalid toleration operator": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "foo",
|
||||
"operator": "In",
|
||||
"value": "bar",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
"value must be empty when `operator` is 'Exists'": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
api.TolerationsAnnotationKey: `
|
||||
[{
|
||||
"key": "foo",
|
||||
"operator": "Exists",
|
||||
"value": "bar",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
if errs := ValidatePod(&v); len(errs) == 0 {
|
||||
@@ -3885,6 +4004,32 @@ func TestValidateNode(t *testing.T) {
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dedicated-node1",
|
||||
// Add a valid taint to a node
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: `
|
||||
[{
|
||||
"key": "GPU",
|
||||
"value": "true",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{
|
||||
{Type: api.NodeLegacyHostIP, Address: "something"},
|
||||
},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidateNode(&successCase); len(errs) != 0 {
|
||||
@@ -3936,6 +4081,119 @@ func TestValidateNode(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"missing-taint-key": {
|
||||
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dedicated-node1",
|
||||
// Add a taint with an empty key to a node
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: `
|
||||
[{
|
||||
"key": "",
|
||||
"value": "special-user-1",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
"bad-taint-key": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dedicated-node1",
|
||||
// Add a taint with an empty key to a node
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: `
|
||||
[{
|
||||
"key": "NoUppercaseOrSpecialCharsLike=Equals",
|
||||
"value": "special-user-1",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
"bad-taint-value": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dedicated-node2",
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: `
|
||||
[{
|
||||
"key": "dedicated",
|
||||
"value": "some\\bad\\value",
|
||||
"effect": "NoSchedule"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{
|
||||
{Type: api.NodeLegacyHostIP, Address: "something"},
|
||||
},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
// Add a taint with an empty value to a node
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
"missing-taint-effect": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dedicated-node3",
|
||||
// Add a taint with an empty effect to a node
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: `
|
||||
[{
|
||||
"key": "dedicated",
|
||||
"value": "special-user-3",
|
||||
"effect": ""
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{
|
||||
{Type: api.NodeLegacyHostIP, Address: "something"},
|
||||
},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
"invalide-taint-effect": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dedicated-node3",
|
||||
// Add a taint with an empty effect to a node
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: `
|
||||
[{
|
||||
"key": "dedicated",
|
||||
"value": "special-user-3",
|
||||
"effect": "NoExecute"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{
|
||||
{Type: api.NodeLegacyHostIP, Address: "something"},
|
||||
},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateNode(&v)
|
||||
@@ -3945,14 +4203,19 @@ func TestValidateNode(t *testing.T) {
|
||||
for i := range errs {
|
||||
field := errs[i].Field
|
||||
expectedFields := map[string]bool{
|
||||
"metadata.name": true,
|
||||
"metadata.labels": true,
|
||||
"metadata.annotations": true,
|
||||
"metadata.namespace": true,
|
||||
"spec.externalID": true,
|
||||
"metadata.name": true,
|
||||
"metadata.labels": true,
|
||||
"metadata.annotations": true,
|
||||
"metadata.namespace": true,
|
||||
"spec.externalID": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].key": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].value": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].effect": true,
|
||||
}
|
||||
if expectedFields[field] == false {
|
||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||
if val, ok := expectedFields[field]; ok {
|
||||
if !val {
|
||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ Find more information at https://github.com/kubernetes/kubernetes.`,
|
||||
|
||||
cmds.AddCommand(NewCmdLabel(f, out))
|
||||
cmds.AddCommand(NewCmdAnnotate(f, out))
|
||||
cmds.AddCommand(NewCmdTaint(f, out))
|
||||
|
||||
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out))
|
||||
cmds.AddCommand(NewCmdClusterInfo(f, out))
|
||||
|
||||
397
pkg/kubectl/cmd/taint.go
Normal file
397
pkg/kubectl/cmd/taint.go
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||
"k8s.io/kubernetes/pkg/util/validation"
|
||||
)
|
||||
|
||||
// TaintOptions have the data required to perform the taint operation
|
||||
type TaintOptions struct {
|
||||
resources []string
|
||||
taintsToAdd []api.Taint
|
||||
removeTaintKeys []string
|
||||
builder *resource.Builder
|
||||
selector string
|
||||
overwrite bool
|
||||
all bool
|
||||
f *cmdutil.Factory
|
||||
out io.Writer
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
const (
|
||||
taint_long = `Update the taints on one or more nodes.
|
||||
|
||||
A taint consists of a key, value, and effect. As an argument here, it is expressed as key=value:effect.
|
||||
The key must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[1]d characters.
|
||||
The value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[1]d characters.
|
||||
The effect must be NoSchedule or PreferNoSchedule.
|
||||
Currently taint can only apply to node.`
|
||||
taint_example = `# Update node 'foo' with a taint with key 'dedicated' and value 'special-user' and effect 'NoSchedule'.
|
||||
# If a taint with that key already exists, its value and effect are replaced as specified.
|
||||
kubectl taint nodes foo dedicated=special-user:NoSchedule
|
||||
# Remove from node 'foo' the taint with key 'dedicated' if one exists.
|
||||
kubectl taint nodes foo dedicated-`
|
||||
)
|
||||
|
||||
func NewCmdTaint(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &TaintOptions{}
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs := []string{}
|
||||
p, err := f.Printer(nil, false, false, false, false, false, false, []string{})
|
||||
cmdutil.CheckErr(err)
|
||||
if p != nil {
|
||||
validArgs = p.HandledResources()
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N",
|
||||
Short: "Update the taints on one or more nodes",
|
||||
Long: fmt.Sprintf(taint_long, validation.DNS1123SubdomainMaxLength, validation.LabelValueMaxLength),
|
||||
Example: taint_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := options.Complete(f, out, cmd, args); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := options.Validate(args); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
|
||||
}
|
||||
if err := options.RunTaint(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
}
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmd.Flags().StringVarP(&options.selector, "selector", "l", "", "Selector (label query) to filter on")
|
||||
cmd.Flags().BoolVar(&options.overwrite, "overwrite", false, "If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.")
|
||||
cmd.Flags().BoolVar(&options.all, "all", false, "select all nodes in the cluster")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func deleteTaintByKey(taints []api.Taint, key string) ([]api.Taint, error) {
|
||||
newTaints := []api.Taint{}
|
||||
found := false
|
||||
for _, taint := range taints {
|
||||
if taint.Key == key {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taint)
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, fmt.Errorf("taint key=\"%s\" not found.", key)
|
||||
}
|
||||
return newTaints, nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
func reorganizeTaints(accessor meta.Object, overwrite bool, taintsToAdd []api.Taint, removeKeys []string) ([]api.Taint, error) {
|
||||
newTaints := append([]api.Taint{}, taintsToAdd...)
|
||||
|
||||
var oldTaints []api.Taint
|
||||
var err error
|
||||
annotations := accessor.GetAnnotations()
|
||||
if annotations != nil {
|
||||
if oldTaints, err = api.GetTaintsFromNodeAnnotations(annotations); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// add taints that already existing but not updated to newTaints
|
||||
for _, oldTaint := range oldTaints {
|
||||
existsInNew := false
|
||||
for _, taint := range newTaints {
|
||||
if taint.Key == oldTaint.Key {
|
||||
existsInNew = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !existsInNew {
|
||||
newTaints = append(newTaints, oldTaint)
|
||||
}
|
||||
}
|
||||
|
||||
allErrs := []error{}
|
||||
for _, taintToRemove := range removeKeys {
|
||||
newTaints, err = deleteTaintByKey(newTaints, taintToRemove)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
}
|
||||
return newTaints, utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func parseTaints(spec []string) ([]api.Taint, []string, error) {
|
||||
var taints []api.Taint
|
||||
var remove []string
|
||||
for _, taintSpec := range spec {
|
||||
if strings.Index(taintSpec, "=") != -1 && strings.Index(taintSpec, ":") != -1 {
|
||||
parts := strings.Split(taintSpec, "=")
|
||||
if len(parts) != 2 || len(parts[1]) == 0 || len(validation.IsQualifiedName(parts[0])) > 0 {
|
||||
return nil, nil, fmt.Errorf("invalid taint spec: %v", taintSpec)
|
||||
}
|
||||
|
||||
parts2 := strings.Split(parts[1], ":")
|
||||
errs := validation.IsValidLabelValue(parts2[0])
|
||||
if len(parts2) != 2 || len(errs) != 0 {
|
||||
return nil, nil, fmt.Errorf("invalid taint spec: %v, %s", taintSpec, strings.Join(errs, "; "))
|
||||
}
|
||||
|
||||
if parts2[1] != string(api.TaintEffectNoSchedule) && parts2[1] != string(api.TaintEffectPreferNoSchedule) {
|
||||
return nil, nil, fmt.Errorf("invalid taint spec: %v, unsupported taint effect", taintSpec)
|
||||
}
|
||||
|
||||
effect := api.TaintEffect(parts2[1])
|
||||
newTaint := api.Taint{
|
||||
Key: parts[0],
|
||||
Value: parts2[0],
|
||||
Effect: effect,
|
||||
}
|
||||
|
||||
taints = append(taints, newTaint)
|
||||
} else if strings.HasSuffix(taintSpec, "-") {
|
||||
remove = append(remove, taintSpec[:len(taintSpec)-1])
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("unknown taint spec: %v", taintSpec)
|
||||
}
|
||||
}
|
||||
return taints, remove, nil
|
||||
}
|
||||
|
||||
// Complete adapts from the command line args and factory to the data required.
|
||||
func (o *TaintOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// retrieves resource and taint args from args
|
||||
// also checks args to verify that all resources are specified before taints
|
||||
taintArgs := []string{}
|
||||
metTaintArg := false
|
||||
for _, s := range args {
|
||||
isTaint := strings.Contains(s, "=") || strings.HasSuffix(s, "-")
|
||||
switch {
|
||||
case !metTaintArg && isTaint:
|
||||
metTaintArg = true
|
||||
fallthrough
|
||||
case metTaintArg && isTaint:
|
||||
taintArgs = append(taintArgs, s)
|
||||
case !metTaintArg && !isTaint:
|
||||
o.resources = append(o.resources, s)
|
||||
case metTaintArg && !isTaint:
|
||||
return fmt.Errorf("all resources must be specified before taint changes: %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
if len(o.resources) < 1 {
|
||||
return fmt.Errorf("one or more resources must be specified as <resource> <name>")
|
||||
}
|
||||
if len(taintArgs) < 1 {
|
||||
return fmt.Errorf("at least one taint update is required")
|
||||
}
|
||||
|
||||
if o.taintsToAdd, o.removeTaintKeys, err = parseTaints(taintArgs); err != nil {
|
||||
return cmdutil.UsageError(cmd, err.Error())
|
||||
}
|
||||
|
||||
mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
|
||||
o.builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace()
|
||||
if o.all {
|
||||
o.builder = o.builder.SelectAllParam(o.all).ResourceTypes("node")
|
||||
} else {
|
||||
if len(o.resources) < 2 {
|
||||
return fmt.Errorf("at least one resource name must be specified since 'all' parameter is not set")
|
||||
}
|
||||
o.builder = o.builder.ResourceNames("node", o.resources[1:]...)
|
||||
}
|
||||
o.builder = o.builder.SelectorParam(o.selector).
|
||||
Flatten().
|
||||
Latest()
|
||||
|
||||
o.f = f
|
||||
o.out = out
|
||||
o.cmd = cmd
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks to the TaintOptions to see if there is sufficient information run the command.
|
||||
func (o TaintOptions) Validate(args []string) error {
|
||||
resourceType := strings.ToLower(o.resources[0])
|
||||
if resourceType != "node" && resourceType != "nodes" {
|
||||
return fmt.Errorf("invalid resource type %s, only node(s) is supported", o.resources[0])
|
||||
}
|
||||
|
||||
// check the format of taint args and checks removed taints aren't in the new taints list
|
||||
conflictKeys := []string{}
|
||||
removeTaintKeysSet := sets.NewString(o.removeTaintKeys...)
|
||||
for _, taint := range o.taintsToAdd {
|
||||
if removeTaintKeysSet.Has(taint.Key) {
|
||||
conflictKeys = append(conflictKeys, taint.Key)
|
||||
}
|
||||
}
|
||||
if len(conflictKeys) > 0 {
|
||||
return fmt.Errorf("can not both modify and remove the following taint(s) in the same command: %s", strings.Join(conflictKeys, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunTaint does the work
|
||||
func (o TaintOptions) RunTaint() error {
|
||||
r := o.builder.Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name, namespace := info.Name, info.Namespace
|
||||
oldData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := o.updateTaints(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
newData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
||||
createdPatch := err == nil
|
||||
if err != nil {
|
||||
glog.V(2).Infof("couldn't compute patch: %v", err)
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := o.f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
|
||||
var outputObj runtime.Object
|
||||
if createdPatch {
|
||||
outputObj, err = helper.Patch(namespace, name, api.StrategicMergePatchType, patchBytes)
|
||||
} else {
|
||||
outputObj, err = helper.Replace(namespace, name, false, obj)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mapper, _ := o.f.Object(cmdutil.GetIncludeThirdPartyAPIs(o.cmd))
|
||||
outputFormat := cmdutil.GetFlagString(o.cmd, "output")
|
||||
if outputFormat != "" {
|
||||
return o.f.PrintObject(o.cmd, mapper, outputObj, o.out)
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(mapper, false, o.out, info.Mapping.Resource, info.Name, "tainted")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// validateNoTaintOverwrites validates that when overwrite is false, to-be-updated taints don't exist in the node taint list (yet)
|
||||
func validateNoTaintOverwrites(accessor meta.Object, taints []api.Taint) error {
|
||||
annotations := accessor.GetAnnotations()
|
||||
if annotations == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
allErrs := []error{}
|
||||
oldTaints, err := api.GetTaintsFromNodeAnnotations(annotations)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
for _, taint := range taints {
|
||||
for _, oldTaint := range oldTaints {
|
||||
if taint.Key == oldTaint.Key {
|
||||
allErrs = append(allErrs, fmt.Errorf("Node '%s' already has a taint (%+v), and --overwrite is false", accessor.GetName(), taint))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
// updateTaints updates taints of obj
|
||||
func (o TaintOptions) updateTaints(obj runtime.Object) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !o.overwrite {
|
||||
if err := validateNoTaintOverwrites(accessor, o.taintsToAdd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
annotations := accessor.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
newTaints, err := reorganizeTaints(accessor, o.overwrite, o.taintsToAdd, o.removeTaintKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
taintsData, err := json.Marshal(newTaints)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
annotations[api.TaintsAnnotationKey] = string(taintsData)
|
||||
accessor.SetAnnotations(annotations)
|
||||
|
||||
return nil
|
||||
}
|
||||
299
pkg/kubectl/cmd/taint_test.go
Normal file
299
pkg/kubectl/cmd/taint_test.go
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/fake"
|
||||
"k8s.io/kubernetes/pkg/conversion"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func generateNodeAndTaintedNode(oldTaints []api.Taint, newTaints []api.Taint) (*api.Node, *api.Node) {
|
||||
var taintedNode *api.Node
|
||||
|
||||
oldTaintsData, _ := json.Marshal(oldTaints)
|
||||
// Create a node.
|
||||
node := &api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "node-name",
|
||||
CreationTimestamp: unversioned.Time{Time: time.Now()},
|
||||
Annotations: map[string]string{
|
||||
api.TaintsAnnotationKey: string(oldTaintsData),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "node-name",
|
||||
},
|
||||
Status: api.NodeStatus{},
|
||||
}
|
||||
clone, _ := conversion.NewCloner().DeepCopy(node)
|
||||
|
||||
newTaintsData, _ := json.Marshal(newTaints)
|
||||
// A copy of the same node, but tainted.
|
||||
taintedNode = clone.(*api.Node)
|
||||
taintedNode.Annotations = map[string]string{
|
||||
api.TaintsAnnotationKey: string(newTaintsData),
|
||||
}
|
||||
|
||||
return node, taintedNode
|
||||
}
|
||||
|
||||
func AnnotationsHaveEqualTaints(annotationA map[string]string, annotationB map[string]string) bool {
|
||||
taintsA, err := api.GetTaintsFromNodeAnnotations(annotationA)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
taintsB, err := api.GetTaintsFromNodeAnnotations(annotationB)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(taintsA) != len(taintsB) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, taintA := range taintsA {
|
||||
found := false
|
||||
for _, taintB := range taintsB {
|
||||
if reflect.DeepEqual(taintA, taintB) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestTaint(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
oldTaints []api.Taint
|
||||
newTaints []api.Taint
|
||||
args []string
|
||||
expectFatal bool
|
||||
expectTaint bool
|
||||
}{
|
||||
// success cases
|
||||
{
|
||||
description: "taints a node with effect NoSchedule",
|
||||
newTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "NoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "foo=bar:NoSchedule"},
|
||||
expectFatal: false,
|
||||
expectTaint: true,
|
||||
},
|
||||
{
|
||||
description: "taints a node with effect PreferNoSchedule",
|
||||
newTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "PreferNoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "foo=bar:PreferNoSchedule"},
|
||||
expectFatal: false,
|
||||
expectTaint: true,
|
||||
},
|
||||
{
|
||||
description: "update an existing taint on the node, change the effect from NoSchedule to PreferNoSchedule",
|
||||
oldTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "NoSchedule",
|
||||
}},
|
||||
newTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "PreferNoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "foo=bar:PreferNoSchedule", "--overwrite"},
|
||||
expectFatal: false,
|
||||
expectTaint: true,
|
||||
},
|
||||
{
|
||||
description: "taints a node with two taints",
|
||||
newTaints: []api.Taint{{
|
||||
Key: "dedicated",
|
||||
Value: "namespaceA",
|
||||
Effect: "NoSchedule",
|
||||
}, {
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "PreferNoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "dedicated=namespaceA:NoSchedule", "foo=bar:PreferNoSchedule"},
|
||||
expectFatal: false,
|
||||
expectTaint: true,
|
||||
},
|
||||
{
|
||||
description: "node has two taints, remove one of them",
|
||||
oldTaints: []api.Taint{{
|
||||
Key: "dedicated",
|
||||
Value: "namespaceA",
|
||||
Effect: "NoSchedule",
|
||||
}, {
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "PreferNoSchedule",
|
||||
}},
|
||||
newTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "PreferNoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "dedicated-"},
|
||||
expectFatal: false,
|
||||
expectTaint: true,
|
||||
},
|
||||
{
|
||||
description: "node has two taints, update one of them and remove the other",
|
||||
oldTaints: []api.Taint{{
|
||||
Key: "dedicated",
|
||||
Value: "namespaceA",
|
||||
Effect: "NoSchedule",
|
||||
}, {
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "PreferNoSchedule",
|
||||
}},
|
||||
newTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "NoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "dedicated-", "foo=bar:NoSchedule", "--overwrite"},
|
||||
expectFatal: false,
|
||||
expectTaint: true,
|
||||
},
|
||||
|
||||
// error cases
|
||||
{
|
||||
description: "invalid taint key",
|
||||
args: []string{"node", "node-name", "nospecialchars^@=banana:NoSchedule"},
|
||||
expectFatal: true,
|
||||
expectTaint: false,
|
||||
},
|
||||
{
|
||||
description: "invalid taint effect",
|
||||
args: []string{"node", "node-name", "foo=bar:NoExcute"},
|
||||
expectFatal: true,
|
||||
expectTaint: false,
|
||||
},
|
||||
{
|
||||
description: "can't update existing taint on the node, since 'overwrite' flag is not set",
|
||||
oldTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "NoSchedule",
|
||||
}},
|
||||
newTaints: []api.Taint{{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
Effect: "NoSchedule",
|
||||
}},
|
||||
args: []string{"node", "node-name", "foo=bar:PreferNoSchedule"},
|
||||
expectFatal: true,
|
||||
expectTaint: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
oldNode, expectNewNode := generateNodeAndTaintedNode(test.oldTaints, test.newTaints)
|
||||
|
||||
new_node := &api.Node{}
|
||||
tainted := false
|
||||
f, tf, codec := NewAPIFactory()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
Codec: codec,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
m := &MyReq{req}
|
||||
switch {
|
||||
case m.isFor("GET", "/nodes/node-name"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, oldNode)}, nil
|
||||
case m.isFor("PATCH", "/nodes/node-name"), m.isFor("PUT", "/nodes/node-name"):
|
||||
tainted = true
|
||||
data, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
if err := runtime.DecodeInto(codec, data, new_node); err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if !AnnotationsHaveEqualTaints(expectNewNode.Annotations, new_node.Annotations) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, expectNewNode.Annotations, new_node.Annotations)
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, new_node)}, nil
|
||||
default:
|
||||
t.Fatalf("%s: unexpected request: %v %#v\n%#v", test.description, req.Method, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfig = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdTaint(f, buf)
|
||||
|
||||
saw_fatal := false
|
||||
func() {
|
||||
defer func() {
|
||||
// Recover from the panic below.
|
||||
_ = recover()
|
||||
// Restore cmdutil behavior
|
||||
cmdutil.DefaultBehaviorOnFatal()
|
||||
}()
|
||||
cmdutil.BehaviorOnFatal(func(e string) { saw_fatal = true; panic(e) })
|
||||
cmd.SetArgs(test.args)
|
||||
cmd.Execute()
|
||||
}()
|
||||
|
||||
if test.expectFatal {
|
||||
if !saw_fatal {
|
||||
t.Fatalf("%s: unexpected non-error", test.description)
|
||||
}
|
||||
}
|
||||
|
||||
if test.expectTaint {
|
||||
if !tainted {
|
||||
t.Fatalf("%s: node not tainted", test.description)
|
||||
}
|
||||
}
|
||||
if !test.expectTaint {
|
||||
if tainted {
|
||||
t.Fatalf("%s: unexpected taint", test.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1617,6 +1617,7 @@ func describeNode(node *api.Node, nodeNonTerminatedPodsList *api.PodList, events
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", node.Name)
|
||||
printLabelsMultiline(out, "Labels", node.Labels)
|
||||
printTaintsInAnnotationMultiline(out, "Taints", node.Annotations)
|
||||
fmt.Fprintf(out, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z))
|
||||
fmt.Fprintf(out, "Phase:\t%v\n", node.Status.Phase)
|
||||
if len(node.Status.Conditions) > 0 {
|
||||
@@ -2256,3 +2257,42 @@ func printLabelsMultilineWithIndent(out io.Writer, initialIndent, title, innerIn
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// printTaintsMultiline prints multiple taints with a proper alignment.
|
||||
func printTaintsInAnnotationMultiline(out io.Writer, title string, annotations map[string]string) {
|
||||
taints, err := api.GetTaintsFromNodeAnnotations(annotations)
|
||||
if err != nil {
|
||||
taints = []api.Taint{}
|
||||
}
|
||||
printTaintsMultilineWithIndent(out, "", title, "\t", taints)
|
||||
}
|
||||
|
||||
// printTaintsMultilineWithIndent prints multiple taints with a user-defined alignment.
|
||||
func printTaintsMultilineWithIndent(out io.Writer, initialIndent, title, innerIndent string, taints []api.Taint) {
|
||||
fmt.Fprintf(out, "%s%s:%s", initialIndent, title, innerIndent)
|
||||
|
||||
if taints == nil || len(taints) == 0 {
|
||||
fmt.Fprintln(out, "<none>")
|
||||
return
|
||||
}
|
||||
|
||||
// to print taints in the sorted order
|
||||
keys := make([]string, 0, len(taints))
|
||||
for _, taint := range taints {
|
||||
keys = append(keys, taint.Key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i, key := range keys {
|
||||
for _, taint := range taints {
|
||||
if taint.Key == key {
|
||||
if i != 0 {
|
||||
fmt.Fprint(out, initialIndent)
|
||||
fmt.Fprint(out, innerIndent)
|
||||
}
|
||||
fmt.Fprintf(out, "%s=%s:%s\n", taint.Key, taint.Value, taint.Effect)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user