mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 01:06:27 +00:00
implement taints and tolerations
This commit is contained in:
parent
952e8302fb
commit
52fb89ff73
@ -55,6 +55,7 @@ docs/man/man1/kubectl-run.1
|
|||||||
docs/man/man1/kubectl-scale.1
|
docs/man/man1/kubectl-scale.1
|
||||||
docs/man/man1/kubectl-set.1
|
docs/man/man1/kubectl-set.1
|
||||||
docs/man/man1/kubectl-stop.1
|
docs/man/man1/kubectl-stop.1
|
||||||
|
docs/man/man1/kubectl-taint.1
|
||||||
docs/man/man1/kubectl-uncordon.1
|
docs/man/man1/kubectl-uncordon.1
|
||||||
docs/man/man1/kubectl-version.1
|
docs/man/man1/kubectl-version.1
|
||||||
docs/man/man1/kubectl.1
|
docs/man/man1/kubectl.1
|
||||||
@ -108,6 +109,7 @@ docs/user-guide/kubectl/kubectl_rollout_undo.md
|
|||||||
docs/user-guide/kubectl/kubectl_run.md
|
docs/user-guide/kubectl/kubectl_run.md
|
||||||
docs/user-guide/kubectl/kubectl_scale.md
|
docs/user-guide/kubectl/kubectl_scale.md
|
||||||
docs/user-guide/kubectl/kubectl_set.md
|
docs/user-guide/kubectl/kubectl_set.md
|
||||||
|
docs/user-guide/kubectl/kubectl_taint.md
|
||||||
docs/user-guide/kubectl/kubectl_uncordon.md
|
docs/user-guide/kubectl/kubectl_uncordon.md
|
||||||
docs/user-guide/kubectl/kubectl_version.md
|
docs/user-guide/kubectl/kubectl_version.md
|
||||||
docs/yaml/kubectl/kubectl.yaml
|
docs/yaml/kubectl/kubectl.yaml
|
||||||
@ -142,5 +144,6 @@ docs/yaml/kubectl/kubectl_run.yaml
|
|||||||
docs/yaml/kubectl/kubectl_scale.yaml
|
docs/yaml/kubectl/kubectl_scale.yaml
|
||||||
docs/yaml/kubectl/kubectl_set.yaml
|
docs/yaml/kubectl/kubectl_set.yaml
|
||||||
docs/yaml/kubectl/kubectl_stop.yaml
|
docs/yaml/kubectl/kubectl_stop.yaml
|
||||||
|
docs/yaml/kubectl/kubectl_taint.yaml
|
||||||
docs/yaml/kubectl/kubectl_uncordon.yaml
|
docs/yaml/kubectl/kubectl_uncordon.yaml
|
||||||
docs/yaml/kubectl/kubectl_version.yaml
|
docs/yaml/kubectl/kubectl_version.yaml
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
- [Other notable changes](#other-notable-changes)
|
- [Other notable changes](#other-notable-changes)
|
||||||
- [v1.3.0-alpha.3](#v130-alpha3)
|
- [v1.3.0-alpha.3](#v130-alpha3)
|
||||||
- [Downloads](#downloads)
|
- [Downloads](#downloads)
|
||||||
- [v1.3.0-alpha.3](#v130-alpha3)
|
|
||||||
- [Changes since v1.3.0-alpha.2](#changes-since-v130-alpha2)
|
- [Changes since v1.3.0-alpha.2](#changes-since-v130-alpha2)
|
||||||
- [Action Required](#action-required)
|
- [Action Required](#action-required)
|
||||||
- [Other notable changes](#other-notable-changes)
|
- [Other notable changes](#other-notable-changes)
|
||||||
|
@ -2955,6 +2955,96 @@ _kubectl_annotate()
|
|||||||
noun_aliases+=("svc")
|
noun_aliases+=("svc")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_kubectl_taint()
|
||||||
|
{
|
||||||
|
last_command="kubectl_taint"
|
||||||
|
commands=()
|
||||||
|
|
||||||
|
flags=()
|
||||||
|
two_word_flags=()
|
||||||
|
flags_with_completion=()
|
||||||
|
flags_completion=()
|
||||||
|
|
||||||
|
flags+=("--all")
|
||||||
|
flags+=("--include-extended-apis")
|
||||||
|
flags+=("--no-headers")
|
||||||
|
flags+=("--output=")
|
||||||
|
two_word_flags+=("-o")
|
||||||
|
flags+=("--output-version=")
|
||||||
|
flags+=("--overwrite")
|
||||||
|
flags+=("--schema-cache-dir=")
|
||||||
|
flags_with_completion+=("--schema-cache-dir")
|
||||||
|
flags_completion+=("_filedir")
|
||||||
|
flags+=("--selector=")
|
||||||
|
two_word_flags+=("-l")
|
||||||
|
flags+=("--show-all")
|
||||||
|
flags+=("-a")
|
||||||
|
flags+=("--show-labels")
|
||||||
|
flags+=("--sort-by=")
|
||||||
|
flags+=("--template=")
|
||||||
|
flags_with_completion+=("--template")
|
||||||
|
flags_completion+=("_filedir")
|
||||||
|
flags+=("--validate")
|
||||||
|
flags+=("--alsologtostderr")
|
||||||
|
flags+=("--api-version=")
|
||||||
|
flags+=("--as=")
|
||||||
|
flags+=("--certificate-authority=")
|
||||||
|
flags+=("--client-certificate=")
|
||||||
|
flags+=("--client-key=")
|
||||||
|
flags+=("--cluster=")
|
||||||
|
flags+=("--context=")
|
||||||
|
flags+=("--insecure-skip-tls-verify")
|
||||||
|
flags+=("--kubeconfig=")
|
||||||
|
flags+=("--log-backtrace-at=")
|
||||||
|
flags+=("--log-dir=")
|
||||||
|
flags+=("--log-flush-frequency=")
|
||||||
|
flags+=("--logtostderr")
|
||||||
|
flags+=("--match-server-version")
|
||||||
|
flags+=("--namespace=")
|
||||||
|
flags_with_completion+=("--namespace")
|
||||||
|
flags_completion+=("__kubectl_get_namespaces")
|
||||||
|
flags+=("--password=")
|
||||||
|
flags+=("--server=")
|
||||||
|
two_word_flags+=("-s")
|
||||||
|
flags+=("--stderrthreshold=")
|
||||||
|
flags+=("--token=")
|
||||||
|
flags+=("--user=")
|
||||||
|
flags+=("--username=")
|
||||||
|
flags+=("--v=")
|
||||||
|
flags+=("--vmodule=")
|
||||||
|
|
||||||
|
must_have_one_flag=()
|
||||||
|
must_have_one_noun=()
|
||||||
|
must_have_one_noun+=("cluster")
|
||||||
|
must_have_one_noun+=("componentstatus")
|
||||||
|
must_have_one_noun+=("configmap")
|
||||||
|
must_have_one_noun+=("daemonset")
|
||||||
|
must_have_one_noun+=("deployment")
|
||||||
|
must_have_one_noun+=("endpoints")
|
||||||
|
must_have_one_noun+=("event")
|
||||||
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("ingress")
|
||||||
|
must_have_one_noun+=("job")
|
||||||
|
must_have_one_noun+=("limitrange")
|
||||||
|
must_have_one_noun+=("namespace")
|
||||||
|
must_have_one_noun+=("node")
|
||||||
|
must_have_one_noun+=("persistentvolume")
|
||||||
|
must_have_one_noun+=("persistentvolumeclaim")
|
||||||
|
must_have_one_noun+=("petset")
|
||||||
|
must_have_one_noun+=("pod")
|
||||||
|
must_have_one_noun+=("podsecuritypolicy")
|
||||||
|
must_have_one_noun+=("podtemplate")
|
||||||
|
must_have_one_noun+=("replicaset")
|
||||||
|
must_have_one_noun+=("replicationcontroller")
|
||||||
|
must_have_one_noun+=("resourcequota")
|
||||||
|
must_have_one_noun+=("secret")
|
||||||
|
must_have_one_noun+=("service")
|
||||||
|
must_have_one_noun+=("serviceaccount")
|
||||||
|
must_have_one_noun+=("thirdpartyresource")
|
||||||
|
must_have_one_noun+=("thirdpartyresourcedata")
|
||||||
|
noun_aliases=()
|
||||||
|
}
|
||||||
|
|
||||||
_kubectl_config_view()
|
_kubectl_config_view()
|
||||||
{
|
{
|
||||||
last_command="kubectl_config_view"
|
last_command="kubectl_config_view"
|
||||||
@ -3648,6 +3738,7 @@ _kubectl()
|
|||||||
commands+=("rollout")
|
commands+=("rollout")
|
||||||
commands+=("label")
|
commands+=("label")
|
||||||
commands+=("annotate")
|
commands+=("annotate")
|
||||||
|
commands+=("taint")
|
||||||
commands+=("config")
|
commands+=("config")
|
||||||
commands+=("cluster-info")
|
commands+=("cluster-info")
|
||||||
commands+=("api-versions")
|
commands+=("api-versions")
|
||||||
|
203
docs/man/man1/kubectl-taint.1
Normal file
203
docs/man/man1/kubectl-taint.1
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" ""
|
||||||
|
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
.PP
|
||||||
|
kubectl taint \- Update the taints on one or more nodes
|
||||||
|
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.PP
|
||||||
|
\fBkubectl taint\fP [OPTIONS]
|
||||||
|
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
Update the taints on one or more nodes.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
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 253 characters.
|
||||||
|
The value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 253 characters.
|
||||||
|
The effect must be NoSchedule or PreferNoSchedule.
|
||||||
|
Currently taint can only apply to node.
|
||||||
|
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.PP
|
||||||
|
\fB\-\-all\fP=false
|
||||||
|
select all nodes in the cluster
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-include\-extended\-apis\fP=true
|
||||||
|
If true, include definitions of new APIs via calls to the API server. [default true]
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-no\-headers\fP=false
|
||||||
|
When using the default output, don't print headers.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-o\fP, \fB\-\-output\fP=""
|
||||||
|
Output format. One of: json|yaml|wide|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=... See golang template [
|
||||||
|
\[la]http://golang.org/pkg/text/template/#pkg-overview\[ra]] and jsonpath template [
|
||||||
|
\[la]http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md\[ra]].
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-output\-version\fP=""
|
||||||
|
Output the formatted object with the given group version (for ex: 'extensions/v1beta1').
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-overwrite\fP=false
|
||||||
|
If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-schema\-cache\-dir\fP="\~/.kube/schema"
|
||||||
|
If non\-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-l\fP, \fB\-\-selector\fP=""
|
||||||
|
Selector (label query) to filter on
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-a\fP, \fB\-\-show\-all\fP=false
|
||||||
|
When printing, show all resources (default hide terminated pods.)
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-show\-labels\fP=false
|
||||||
|
When printing, show all labels as the last column (default hide labels column)
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-sort\-by\fP=""
|
||||||
|
If non\-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-template\fP=""
|
||||||
|
Template string or path to template file to use when \-o=go\-template, \-o=go\-template\-file. The template format is golang templates [
|
||||||
|
\[la]http://golang.org/pkg/text/template/#pkg-overview\[ra]].
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-validate\fP=true
|
||||||
|
If true, use a schema to validate the input before sending it
|
||||||
|
|
||||||
|
|
||||||
|
.SH OPTIONS INHERITED FROM PARENT COMMANDS
|
||||||
|
.PP
|
||||||
|
\fB\-\-alsologtostderr\fP=false
|
||||||
|
log to standard error as well as files
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-api\-version\fP=""
|
||||||
|
DEPRECATED: The API version to use when talking to the server
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-as\fP=""
|
||||||
|
Username to impersonate for the operation.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-certificate\-authority\fP=""
|
||||||
|
Path to a cert. file for the certificate authority.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-client\-certificate\fP=""
|
||||||
|
Path to a client certificate file for TLS.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-client\-key\fP=""
|
||||||
|
Path to a client key file for TLS.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-cluster\fP=""
|
||||||
|
The name of the kubeconfig cluster to use
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-context\fP=""
|
||||||
|
The name of the kubeconfig context to use
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-insecure\-skip\-tls\-verify\fP=false
|
||||||
|
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-kubeconfig\fP=""
|
||||||
|
Path to the kubeconfig file to use for CLI requests.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-log\-backtrace\-at\fP=:0
|
||||||
|
when logging hits line file:N, emit a stack trace
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-log\-dir\fP=""
|
||||||
|
If non\-empty, write log files in this directory
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-log\-flush\-frequency\fP=5s
|
||||||
|
Maximum number of seconds between log flushes
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-logtostderr\fP=true
|
||||||
|
log to standard error instead of files
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-match\-server\-version\fP=false
|
||||||
|
Require server version to match client version
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-namespace\fP=""
|
||||||
|
If present, the namespace scope for this CLI request.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-password\fP=""
|
||||||
|
Password for basic authentication to the API server.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-s\fP, \fB\-\-server\fP=""
|
||||||
|
The address and port of the Kubernetes API server
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-stderrthreshold\fP=2
|
||||||
|
logs at or above this threshold go to stderr
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-token\fP=""
|
||||||
|
Bearer token for authentication to the API server.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-user\fP=""
|
||||||
|
The name of the kubeconfig user to use
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-username\fP=""
|
||||||
|
Username for basic authentication to the API server.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-v\fP=0
|
||||||
|
log level for V logs
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-vmodule\fP=
|
||||||
|
comma\-separated list of pattern=N settings for file\-filtered logging
|
||||||
|
|
||||||
|
|
||||||
|
.SH EXAMPLE
|
||||||
|
.PP
|
||||||
|
.RS
|
||||||
|
|
||||||
|
.nf
|
||||||
|
# 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\-
|
||||||
|
|
||||||
|
.fi
|
||||||
|
.RE
|
||||||
|
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.PP
|
||||||
|
\fBkubectl(1)\fP,
|
||||||
|
|
||||||
|
|
||||||
|
.SH HISTORY
|
||||||
|
.PP
|
||||||
|
January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since!
|
@ -120,7 +120,7 @@ Find more information at
|
|||||||
|
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.PP
|
.PP
|
||||||
\fBkubectl\-get(1)\fP, \fBkubectl\-set(1)\fP, \fBkubectl\-describe(1)\fP, \fBkubectl\-create(1)\fP, \fBkubectl\-replace(1)\fP, \fBkubectl\-patch(1)\fP, \fBkubectl\-delete(1)\fP, \fBkubectl\-edit(1)\fP, \fBkubectl\-apply(1)\fP, \fBkubectl\-namespace(1)\fP, \fBkubectl\-logs(1)\fP, \fBkubectl\-rolling\-update(1)\fP, \fBkubectl\-scale(1)\fP, \fBkubectl\-cordon(1)\fP, \fBkubectl\-drain(1)\fP, \fBkubectl\-uncordon(1)\fP, \fBkubectl\-attach(1)\fP, \fBkubectl\-exec(1)\fP, \fBkubectl\-port\-forward(1)\fP, \fBkubectl\-proxy(1)\fP, \fBkubectl\-run(1)\fP, \fBkubectl\-stop(1)\fP, \fBkubectl\-expose(1)\fP, \fBkubectl\-autoscale(1)\fP, \fBkubectl\-rollout(1)\fP, \fBkubectl\-label(1)\fP, \fBkubectl\-annotate(1)\fP, \fBkubectl\-config(1)\fP, \fBkubectl\-cluster\-info(1)\fP, \fBkubectl\-api\-versions(1)\fP, \fBkubectl\-version(1)\fP, \fBkubectl\-explain(1)\fP, \fBkubectl\-convert(1)\fP,
|
\fBkubectl\-get(1)\fP, \fBkubectl\-set(1)\fP, \fBkubectl\-describe(1)\fP, \fBkubectl\-create(1)\fP, \fBkubectl\-replace(1)\fP, \fBkubectl\-patch(1)\fP, \fBkubectl\-delete(1)\fP, \fBkubectl\-edit(1)\fP, \fBkubectl\-apply(1)\fP, \fBkubectl\-namespace(1)\fP, \fBkubectl\-logs(1)\fP, \fBkubectl\-rolling\-update(1)\fP, \fBkubectl\-scale(1)\fP, \fBkubectl\-cordon(1)\fP, \fBkubectl\-drain(1)\fP, \fBkubectl\-uncordon(1)\fP, \fBkubectl\-attach(1)\fP, \fBkubectl\-exec(1)\fP, \fBkubectl\-port\-forward(1)\fP, \fBkubectl\-proxy(1)\fP, \fBkubectl\-run(1)\fP, \fBkubectl\-stop(1)\fP, \fBkubectl\-expose(1)\fP, \fBkubectl\-autoscale(1)\fP, \fBkubectl\-rollout(1)\fP, \fBkubectl\-label(1)\fP, \fBkubectl\-annotate(1)\fP, \fBkubectl\-taint(1)\fP, \fBkubectl\-config(1)\fP, \fBkubectl\-cluster\-info(1)\fP, \fBkubectl\-api\-versions(1)\fP, \fBkubectl\-version(1)\fP, \fBkubectl\-explain(1)\fP, \fBkubectl\-convert(1)\fP,
|
||||||
|
|
||||||
|
|
||||||
.SH HISTORY
|
.SH HISTORY
|
||||||
|
@ -107,10 +107,11 @@ kubectl
|
|||||||
* [kubectl run](kubectl_run.md) - Run a particular image on the cluster.
|
* [kubectl run](kubectl_run.md) - Run a particular image on the cluster.
|
||||||
* [kubectl scale](kubectl_scale.md) - Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job.
|
* [kubectl scale](kubectl_scale.md) - Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job.
|
||||||
* [kubectl set](kubectl_set.md) - Set specific features on objects
|
* [kubectl set](kubectl_set.md) - Set specific features on objects
|
||||||
|
* [kubectl taint](kubectl_taint.md) - Update the taints on one or more nodes
|
||||||
* [kubectl uncordon](kubectl_uncordon.md) - Mark node as schedulable
|
* [kubectl uncordon](kubectl_uncordon.md) - Mark node as schedulable
|
||||||
* [kubectl version](kubectl_version.md) - Print the client and server version information.
|
* [kubectl version](kubectl_version.md) - Print the client and server version information.
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 10-May-2016
|
###### Auto generated by spf13/cobra on 15-May-2016
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
[]()
|
[]()
|
||||||
|
113
docs/user-guide/kubectl/kubectl_taint.md
Normal file
113
docs/user-guide/kubectl/kubectl_taint.md
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||||
|
|
||||||
|
<!-- BEGIN STRIP_FOR_RELEASE -->
|
||||||
|
|
||||||
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||||
|
width="25" height="25">
|
||||||
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||||
|
width="25" height="25">
|
||||||
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||||
|
width="25" height="25">
|
||||||
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||||
|
width="25" height="25">
|
||||||
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||||
|
width="25" height="25">
|
||||||
|
|
||||||
|
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
|
||||||
|
|
||||||
|
If you are using a released version of Kubernetes, you should
|
||||||
|
refer to the docs that go with that version.
|
||||||
|
|
||||||
|
Documentation for other releases can be found at
|
||||||
|
[releases.k8s.io](http://releases.k8s.io).
|
||||||
|
</strong>
|
||||||
|
--
|
||||||
|
|
||||||
|
<!-- END STRIP_FOR_RELEASE -->
|
||||||
|
|
||||||
|
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||||
|
|
||||||
|
## kubectl taint
|
||||||
|
|
||||||
|
Update the taints on one or more nodes
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
|
||||||
|
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 253 characters.
|
||||||
|
The value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 253 characters.
|
||||||
|
The effect must be NoSchedule or PreferNoSchedule.
|
||||||
|
Currently taint can only apply to node.
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
# 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-
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
--all[=false]: select all nodes in the cluster
|
||||||
|
--include-extended-apis[=true]: If true, include definitions of new APIs via calls to the API server. [default true]
|
||||||
|
--no-headers[=false]: When using the default output, don't print headers.
|
||||||
|
-o, --output="": Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].
|
||||||
|
--output-version="": Output the formatted object with the given group version (for ex: 'extensions/v1beta1').
|
||||||
|
--overwrite[=false]: If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.
|
||||||
|
--schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
|
||||||
|
-l, --selector="": Selector (label query) to filter on
|
||||||
|
-a, --show-all[=false]: When printing, show all resources (default hide terminated pods.)
|
||||||
|
--show-labels[=false]: When printing, show all labels as the last column (default hide labels column)
|
||||||
|
--sort-by="": If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.
|
||||||
|
--template="": Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
|
||||||
|
--validate[=true]: If true, use a schema to validate the input before sending it
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
--alsologtostderr[=false]: log to standard error as well as files
|
||||||
|
--as="": Username to impersonate for the operation.
|
||||||
|
--certificate-authority="": Path to a cert. file for the certificate authority.
|
||||||
|
--client-certificate="": Path to a client certificate file for TLS.
|
||||||
|
--client-key="": Path to a client key file for TLS.
|
||||||
|
--cluster="": The name of the kubeconfig cluster to use
|
||||||
|
--context="": The name of the kubeconfig context to use
|
||||||
|
--insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
|
||||||
|
--kubeconfig="": Path to the kubeconfig file to use for CLI requests.
|
||||||
|
--log-backtrace-at=:0: when logging hits line file:N, emit a stack trace
|
||||||
|
--log-dir="": If non-empty, write log files in this directory
|
||||||
|
--log-flush-frequency=5s: Maximum number of seconds between log flushes
|
||||||
|
--logtostderr[=true]: log to standard error instead of files
|
||||||
|
--match-server-version[=false]: Require server version to match client version
|
||||||
|
--namespace="": If present, the namespace scope for this CLI request.
|
||||||
|
--password="": Password for basic authentication to the API server.
|
||||||
|
-s, --server="": The address and port of the Kubernetes API server
|
||||||
|
--stderrthreshold=2: logs at or above this threshold go to stderr
|
||||||
|
--token="": Bearer token for authentication to the API server.
|
||||||
|
--user="": The name of the kubeconfig user to use
|
||||||
|
--username="": Username for basic authentication to the API server.
|
||||||
|
--v=0: log level for V logs
|
||||||
|
--vmodule=: comma-separated list of pattern=N settings for file-filtered logging
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEE ALSO
|
||||||
|
|
||||||
|
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||||
|
|
||||||
|
###### Auto generated by spf13/cobra on 17-May-2016
|
||||||
|
|
||||||
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
|
[]()
|
||||||
|
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
@ -93,6 +93,7 @@ see_also:
|
|||||||
- rollout
|
- rollout
|
||||||
- label
|
- label
|
||||||
- annotate
|
- annotate
|
||||||
|
- taint
|
||||||
- config
|
- config
|
||||||
- cluster-info
|
- cluster-info
|
||||||
- api-versions
|
- api-versions
|
||||||
|
127
docs/yaml/kubectl/kubectl_taint.yaml
Normal file
127
docs/yaml/kubectl/kubectl_taint.yaml
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
name: taint
|
||||||
|
synopsis: Update the taints on one or more nodes
|
||||||
|
description: |-
|
||||||
|
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 253 characters.
|
||||||
|
The value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 253 characters.
|
||||||
|
The effect must be NoSchedule or PreferNoSchedule.
|
||||||
|
Currently taint can only apply to node.
|
||||||
|
options:
|
||||||
|
- name: all
|
||||||
|
default_value: "false"
|
||||||
|
usage: select all nodes in the cluster
|
||||||
|
- name: include-extended-apis
|
||||||
|
default_value: "true"
|
||||||
|
usage: |
|
||||||
|
If true, include definitions of new APIs via calls to the API server. [default true]
|
||||||
|
- name: no-headers
|
||||||
|
default_value: "false"
|
||||||
|
usage: When using the default output, don't print headers.
|
||||||
|
- name: output
|
||||||
|
shorthand: o
|
||||||
|
usage: |
|
||||||
|
Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].
|
||||||
|
- name: output-version
|
||||||
|
usage: |
|
||||||
|
Output the formatted object with the given group version (for ex: 'extensions/v1beta1').
|
||||||
|
- name: overwrite
|
||||||
|
default_value: "false"
|
||||||
|
usage: |
|
||||||
|
If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.
|
||||||
|
- name: schema-cache-dir
|
||||||
|
default_value: ~/.kube/schema
|
||||||
|
usage: |
|
||||||
|
If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
|
||||||
|
- name: selector
|
||||||
|
shorthand: l
|
||||||
|
usage: Selector (label query) to filter on
|
||||||
|
- name: show-all
|
||||||
|
shorthand: a
|
||||||
|
default_value: "false"
|
||||||
|
usage: |
|
||||||
|
When printing, show all resources (default hide terminated pods.)
|
||||||
|
- name: show-labels
|
||||||
|
default_value: "false"
|
||||||
|
usage: |
|
||||||
|
When printing, show all labels as the last column (default hide labels column)
|
||||||
|
- name: sort-by
|
||||||
|
usage: |
|
||||||
|
If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.
|
||||||
|
- name: template
|
||||||
|
usage: |
|
||||||
|
Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
|
||||||
|
- name: validate
|
||||||
|
default_value: "true"
|
||||||
|
usage: |
|
||||||
|
If true, use a schema to validate the input before sending it
|
||||||
|
inherited_options:
|
||||||
|
- name: alsologtostderr
|
||||||
|
default_value: "false"
|
||||||
|
usage: log to standard error as well as files
|
||||||
|
- name: api-version
|
||||||
|
usage: |
|
||||||
|
DEPRECATED: The API version to use when talking to the server
|
||||||
|
- name: as
|
||||||
|
usage: Username to impersonate for the operation.
|
||||||
|
- name: certificate-authority
|
||||||
|
usage: Path to a cert. file for the certificate authority.
|
||||||
|
- name: client-certificate
|
||||||
|
usage: Path to a client certificate file for TLS.
|
||||||
|
- name: client-key
|
||||||
|
usage: Path to a client key file for TLS.
|
||||||
|
- name: cluster
|
||||||
|
usage: The name of the kubeconfig cluster to use
|
||||||
|
- name: context
|
||||||
|
usage: The name of the kubeconfig context to use
|
||||||
|
- name: insecure-skip-tls-verify
|
||||||
|
default_value: "false"
|
||||||
|
usage: |
|
||||||
|
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
|
||||||
|
- name: kubeconfig
|
||||||
|
usage: Path to the kubeconfig file to use for CLI requests.
|
||||||
|
- name: log-backtrace-at
|
||||||
|
default_value: :0
|
||||||
|
usage: when logging hits line file:N, emit a stack trace
|
||||||
|
- name: log-dir
|
||||||
|
usage: If non-empty, write log files in this directory
|
||||||
|
- name: log-flush-frequency
|
||||||
|
default_value: 5s
|
||||||
|
usage: Maximum number of seconds between log flushes
|
||||||
|
- name: logtostderr
|
||||||
|
default_value: "true"
|
||||||
|
usage: log to standard error instead of files
|
||||||
|
- name: match-server-version
|
||||||
|
default_value: "false"
|
||||||
|
usage: Require server version to match client version
|
||||||
|
- name: namespace
|
||||||
|
usage: If present, the namespace scope for this CLI request.
|
||||||
|
- name: password
|
||||||
|
usage: Password for basic authentication to the API server.
|
||||||
|
- name: server
|
||||||
|
shorthand: s
|
||||||
|
usage: The address and port of the Kubernetes API server
|
||||||
|
- name: stderrthreshold
|
||||||
|
default_value: "2"
|
||||||
|
usage: logs at or above this threshold go to stderr
|
||||||
|
- name: token
|
||||||
|
usage: Bearer token for authentication to the API server.
|
||||||
|
- name: user
|
||||||
|
usage: The name of the kubeconfig user to use
|
||||||
|
- name: username
|
||||||
|
usage: Username for basic authentication to the API server.
|
||||||
|
- name: v
|
||||||
|
default_value: "0"
|
||||||
|
usage: log level for V logs
|
||||||
|
- name: vmodule
|
||||||
|
usage: |
|
||||||
|
comma-separated list of pattern=N settings for file-filtered logging
|
||||||
|
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-
|
||||||
|
see_also:
|
||||||
|
- kubectl
|
@ -175,6 +175,8 @@ func init() {
|
|||||||
DeepCopy_api_ServiceSpec,
|
DeepCopy_api_ServiceSpec,
|
||||||
DeepCopy_api_ServiceStatus,
|
DeepCopy_api_ServiceStatus,
|
||||||
DeepCopy_api_TCPSocketAction,
|
DeepCopy_api_TCPSocketAction,
|
||||||
|
DeepCopy_api_Taint,
|
||||||
|
DeepCopy_api_Toleration,
|
||||||
DeepCopy_api_Volume,
|
DeepCopy_api_Volume,
|
||||||
DeepCopy_api_VolumeMount,
|
DeepCopy_api_VolumeMount,
|
||||||
DeepCopy_api_VolumeSource,
|
DeepCopy_api_VolumeSource,
|
||||||
@ -2967,6 +2969,21 @@ func DeepCopy_api_TCPSocketAction(in TCPSocketAction, out *TCPSocketAction, c *c
|
|||||||
return nil
|
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 {
|
func DeepCopy_api_Volume(in Volume, out *Volume, c *conversion.Cloner) error {
|
||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
if err := DeepCopy_api_VolumeSource(in.VolumeSource, &out.VolumeSource, c); err != nil {
|
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
|
return selector, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AffinityAnnotationKey represents the key of affinity data (json serialized)
|
const (
|
||||||
// in the Annotations of a Pod.
|
// AffinityAnnotationKey represents the key of affinity data (json serialized)
|
||||||
const AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
|
// 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
|
// GetAffinityFromPod gets the json serialized affinity data from Pod.Annotations
|
||||||
// and converts it to the Affinity type in api.
|
// and converts it to the Affinity type in api.
|
||||||
@ -427,3 +437,61 @@ func GetAffinityFromPodAnnotations(annotations map[string]string) (Affinity, err
|
|||||||
}
|
}
|
||||||
return affinity, nil
|
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)
|
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) {
|
func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||||
var h codecSelfer1234
|
var h codecSelfer1234
|
||||||
z, r := codec1978.GenHelperEncoder(e)
|
z, r := codec1978.GenHelperEncoder(e)
|
||||||
|
@ -1308,6 +1308,73 @@ type PreferredSchedulingTerm struct {
|
|||||||
Preference NodeSelectorTerm `json:"preference"`
|
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
|
// PodSpec is a description of a pod
|
||||||
type PodSpec struct {
|
type PodSpec struct {
|
||||||
Volumes []Volume `json:"volumes"`
|
Volumes []Volume `json:"volumes"`
|
||||||
|
@ -311,6 +311,10 @@ func init() {
|
|||||||
Convert_api_ServiceStatus_To_v1_ServiceStatus,
|
Convert_api_ServiceStatus_To_v1_ServiceStatus,
|
||||||
Convert_v1_TCPSocketAction_To_api_TCPSocketAction,
|
Convert_v1_TCPSocketAction_To_api_TCPSocketAction,
|
||||||
Convert_api_TCPSocketAction_To_v1_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_v1_Volume_To_api_Volume,
|
||||||
Convert_api_Volume_To_v1_Volume,
|
Convert_api_Volume_To_v1_Volume,
|
||||||
Convert_v1_VolumeMount_To_api_VolumeMount,
|
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)
|
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 {
|
func autoConvert_v1_Volume_To_api_Volume(in *Volume, out *api.Volume, s conversion.Scope) error {
|
||||||
SetDefaults_Volume(in)
|
SetDefaults_Volume(in)
|
||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
|
@ -172,6 +172,8 @@ func init() {
|
|||||||
DeepCopy_v1_ServiceSpec,
|
DeepCopy_v1_ServiceSpec,
|
||||||
DeepCopy_v1_ServiceStatus,
|
DeepCopy_v1_ServiceStatus,
|
||||||
DeepCopy_v1_TCPSocketAction,
|
DeepCopy_v1_TCPSocketAction,
|
||||||
|
DeepCopy_v1_Taint,
|
||||||
|
DeepCopy_v1_Toleration,
|
||||||
DeepCopy_v1_Volume,
|
DeepCopy_v1_Volume,
|
||||||
DeepCopy_v1_VolumeMount,
|
DeepCopy_v1_VolumeMount,
|
||||||
DeepCopy_v1_VolumeSource,
|
DeepCopy_v1_VolumeSource,
|
||||||
@ -2928,6 +2930,21 @@ func DeepCopy_v1_TCPSocketAction(in TCPSocketAction, out *TCPSocketAction, c *co
|
|||||||
return nil
|
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 {
|
func DeepCopy_v1_Volume(in Volume, out *Volume, c *conversion.Cloner) error {
|
||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
if err := DeepCopy_v1_VolumeSource(in.VolumeSource, &out.VolumeSource, c); err != nil {
|
if err := DeepCopy_v1_VolumeSource(in.VolumeSource, &out.VolumeSource, c); err != nil {
|
||||||
|
@ -165,6 +165,8 @@ limitations under the License.
|
|||||||
ServiceSpec
|
ServiceSpec
|
||||||
ServiceStatus
|
ServiceStatus
|
||||||
TCPSocketAction
|
TCPSocketAction
|
||||||
|
Taint
|
||||||
|
Toleration
|
||||||
Volume
|
Volume
|
||||||
VolumeMount
|
VolumeMount
|
||||||
VolumeSource
|
VolumeSource
|
||||||
@ -749,6 +751,14 @@ func (m *TCPSocketAction) Reset() { *m = TCPSocketAction{} }
|
|||||||
func (m *TCPSocketAction) String() string { return proto.CompactTextString(m) }
|
func (m *TCPSocketAction) String() string { return proto.CompactTextString(m) }
|
||||||
func (*TCPSocketAction) ProtoMessage() {}
|
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) Reset() { *m = Volume{} }
|
||||||
func (m *Volume) String() string { return proto.CompactTextString(m) }
|
func (m *Volume) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Volume) ProtoMessage() {}
|
func (*Volume) ProtoMessage() {}
|
||||||
@ -906,6 +916,8 @@ func init() {
|
|||||||
proto.RegisterType((*ServiceSpec)(nil), "k8s.io.kubernetes.pkg.api.v1.ServiceSpec")
|
proto.RegisterType((*ServiceSpec)(nil), "k8s.io.kubernetes.pkg.api.v1.ServiceSpec")
|
||||||
proto.RegisterType((*ServiceStatus)(nil), "k8s.io.kubernetes.pkg.api.v1.ServiceStatus")
|
proto.RegisterType((*ServiceStatus)(nil), "k8s.io.kubernetes.pkg.api.v1.ServiceStatus")
|
||||||
proto.RegisterType((*TCPSocketAction)(nil), "k8s.io.kubernetes.pkg.api.v1.TCPSocketAction")
|
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((*Volume)(nil), "k8s.io.kubernetes.pkg.api.v1.Volume")
|
||||||
proto.RegisterType((*VolumeMount)(nil), "k8s.io.kubernetes.pkg.api.v1.VolumeMount")
|
proto.RegisterType((*VolumeMount)(nil), "k8s.io.kubernetes.pkg.api.v1.VolumeMount")
|
||||||
proto.RegisterType((*VolumeSource)(nil), "k8s.io.kubernetes.pkg.api.v1.VolumeSource")
|
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
|
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) {
|
func (m *Volume) Marshal() (data []byte, err error) {
|
||||||
size := m.Size()
|
size := m.Size()
|
||||||
data = make([]byte, size)
|
data = make([]byte, size)
|
||||||
@ -9724,6 +9800,32 @@ func (m *TCPSocketAction) Size() (n int) {
|
|||||||
return n
|
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) {
|
func (m *Volume) Size() (n int) {
|
||||||
var l int
|
var l int
|
||||||
_ = l
|
_ = l
|
||||||
@ -32142,6 +32244,309 @@ func (m *TCPSocketAction) Unmarshal(data []byte) error {
|
|||||||
}
|
}
|
||||||
return nil
|
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 {
|
func (m *Volume) Unmarshal(data []byte) error {
|
||||||
l := len(data)
|
l := len(data)
|
||||||
iNdEx := 0
|
iNdEx := 0
|
||||||
|
@ -2686,6 +2686,42 @@ message TCPSocketAction {
|
|||||||
optional k8s.io.kubernetes.pkg.util.intstr.IntOrString port = 1;
|
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.
|
// Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
message Volume {
|
message Volume {
|
||||||
// Volume's name.
|
// Volume's name.
|
||||||
|
@ -23801,6 +23801,592 @@ func (x *PreferredSchedulingTerm) codecDecodeSelfFromArray(l int, d *codec1978.D
|
|||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
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) {
|
func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||||
var h codecSelfer1234
|
var h codecSelfer1234
|
||||||
z, r := codec1978.GenHelperEncoder(e)
|
z, r := codec1978.GenHelperEncoder(e)
|
||||||
|
@ -1541,6 +1541,73 @@ type PreferredSchedulingTerm struct {
|
|||||||
Preference NodeSelectorTerm `json:"preference" protobuf:"bytes,2,opt,name=preference"`
|
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 (
|
const (
|
||||||
// This annotation key will be used to contain an array of v1 JSON encoded Containers
|
// 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.
|
// 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
|
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{
|
var map_Volume = map[string]string{
|
||||||
"": "Volume represents a named volume in a pod that may be accessed by any container in the pod.",
|
"": "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",
|
"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)...)
|
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) {
|
if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists && !validation.IsDNS1123Label(hostname) {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodHostnameAnnotation, DNS1123LabelErrorMsg))
|
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodHostnameAnnotation, DNS1123LabelErrorMsg))
|
||||||
}
|
}
|
||||||
@ -1462,6 +1466,60 @@ func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference, fldPa
|
|||||||
return allErrors
|
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.
|
// ValidatePod tests if required fields in the pod are set.
|
||||||
func ValidatePod(pod *api.Pod) field.ErrorList {
|
func ValidatePod(pod *api.Pod) field.ErrorList {
|
||||||
fldPath := field.NewPath("metadata")
|
fldPath := field.NewPath("metadata")
|
||||||
@ -1701,6 +1759,22 @@ func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *fi
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
|
||||||
|
func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
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.
|
// ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
|
||||||
func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec, specPath, fldPath *field.Path) field.ErrorList {
|
func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec, specPath, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
@ -2113,9 +2187,51 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path)
|
|||||||
return allErrs
|
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.
|
// ValidateNode tests if required fields in the node are set.
|
||||||
func ValidateNode(node *api.Node) field.ErrorList {
|
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.
|
// 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.
|
// ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode.
|
||||||
func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList {
|
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,
|
// TODO: Enable the code once we have better api object.status update model. Currently,
|
||||||
// anyone can update node status.
|
// anyone can update node status.
|
||||||
|
@ -1954,60 +1954,6 @@ func TestValidatePod(t *testing.T) {
|
|||||||
NodeName: "foobar",
|
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.
|
{ // Serialized affinity requirements in annotations.
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
@ -2160,6 +2106,83 @@ func TestValidateAffinity(t *testing.T) {
|
|||||||
DNSPolicy: api.DNSClusterFirst,
|
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 {
|
for _, pod := range successCases {
|
||||||
if errs := ValidatePod(&pod); len(errs) != 0 {
|
if errs := ValidatePod(&pod); len(errs) != 0 {
|
||||||
@ -2168,6 +2191,42 @@ func TestValidateAffinity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorCases := map[string]api.Pod{
|
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": {
|
"invalid json of node affinity in pod annotations": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
@ -2476,6 +2535,66 @@ func TestValidateAffinity(t *testing.T) {
|
|||||||
DNSPolicy: api.DNSClusterFirst,
|
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 {
|
for k, v := range errorCases {
|
||||||
if errs := ValidatePod(&v); len(errs) == 0 {
|
if errs := ValidatePod(&v); len(errs) == 0 {
|
||||||
@ -3885,6 +4004,32 @@ func TestValidateNode(t *testing.T) {
|
|||||||
ExternalID: "external",
|
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 {
|
for _, successCase := range successCases {
|
||||||
if errs := ValidateNode(&successCase); len(errs) != 0 {
|
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 {
|
for k, v := range errorCases {
|
||||||
errs := ValidateNode(&v)
|
errs := ValidateNode(&v)
|
||||||
@ -3945,14 +4203,19 @@ func TestValidateNode(t *testing.T) {
|
|||||||
for i := range errs {
|
for i := range errs {
|
||||||
field := errs[i].Field
|
field := errs[i].Field
|
||||||
expectedFields := map[string]bool{
|
expectedFields := map[string]bool{
|
||||||
"metadata.name": true,
|
"metadata.name": true,
|
||||||
"metadata.labels": true,
|
"metadata.labels": true,
|
||||||
"metadata.annotations": true,
|
"metadata.annotations": true,
|
||||||
"metadata.namespace": true,
|
"metadata.namespace": true,
|
||||||
"spec.externalID": 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 {
|
if val, ok := expectedFields[field]; ok {
|
||||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
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(NewCmdLabel(f, out))
|
||||||
cmds.AddCommand(NewCmdAnnotate(f, out))
|
cmds.AddCommand(NewCmdAnnotate(f, out))
|
||||||
|
cmds.AddCommand(NewCmdTaint(f, out))
|
||||||
|
|
||||||
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out))
|
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out))
|
||||||
cmds.AddCommand(NewCmdClusterInfo(f, 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 {
|
return tabbedString(func(out io.Writer) error {
|
||||||
fmt.Fprintf(out, "Name:\t%s\n", node.Name)
|
fmt.Fprintf(out, "Name:\t%s\n", node.Name)
|
||||||
printLabelsMultiline(out, "Labels", node.Labels)
|
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, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z))
|
||||||
fmt.Fprintf(out, "Phase:\t%v\n", node.Status.Phase)
|
fmt.Fprintf(out, "Phase:\t%v\n", node.Status.Phase)
|
||||||
if len(node.Status.Conditions) > 0 {
|
if len(node.Status.Conditions) > 0 {
|
||||||
@ -2256,3 +2257,42 @@ func printLabelsMultilineWithIndent(out io.Writer, initialIndent, title, innerIn
|
|||||||
i++
|
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++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ var (
|
|||||||
ErrVolumeZoneConflict = newPredicateFailureError("NoVolumeZoneConflict")
|
ErrVolumeZoneConflict = newPredicateFailureError("NoVolumeZoneConflict")
|
||||||
ErrNodeSelectorNotMatch = newPredicateFailureError("MatchNodeSelector")
|
ErrNodeSelectorNotMatch = newPredicateFailureError("MatchNodeSelector")
|
||||||
ErrPodAffinityNotMatch = newPredicateFailureError("MatchInterPodAffinity")
|
ErrPodAffinityNotMatch = newPredicateFailureError("MatchInterPodAffinity")
|
||||||
|
ErrTaintsTolerationsNotMatch = newPredicateFailureError("PodToleratesNodeTaints")
|
||||||
ErrPodNotMatchHostName = newPredicateFailureError("HostName")
|
ErrPodNotMatchHostName = newPredicateFailureError("HostName")
|
||||||
ErrPodNotFitsHostPorts = newPredicateFailureError("PodFitsHostPorts")
|
ErrPodNotFitsHostPorts = newPredicateFailureError("PodFitsHostPorts")
|
||||||
ErrNodeLabelPresenceViolated = newPredicateFailureError("CheckNodeLabelPresence")
|
ErrNodeLabelPresenceViolated = newPredicateFailureError("CheckNodeLabelPresence")
|
||||||
|
@ -944,3 +944,58 @@ func (checker *PodAffinityChecker) NodeMatchPodAffinityAntiAffinity(pod *api.Pod
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TolerationMatch struct {
|
||||||
|
info NodeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTolerationMatchPredicate(info NodeInfo) algorithm.FitPredicate {
|
||||||
|
tolerationMatch := &TolerationMatch{
|
||||||
|
info: info,
|
||||||
|
}
|
||||||
|
return tolerationMatch.PodToleratesNodeTaints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TolerationMatch) PodToleratesNodeTaints(pod *api.Pod, nodeInfo *schedulercache.NodeInfo) (bool, error) {
|
||||||
|
node := nodeInfo.Node()
|
||||||
|
|
||||||
|
taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tolerations, err := api.GetTolerationsFromPodAnnotations(pod.Annotations)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tolerationsToleratesTaints(tolerations, taints) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, ErrTaintsTolerationsNotMatch
|
||||||
|
}
|
||||||
|
|
||||||
|
func tolerationsToleratesTaints(tolerations []api.Toleration, taints []api.Taint) bool {
|
||||||
|
// If the taint list is nil/empty, it is tolerated by all tolerations by default.
|
||||||
|
if len(taints) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The taint list isn't nil/empty, a nil/empty toleration list can't tolerate them.
|
||||||
|
if len(tolerations) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, taint := range taints {
|
||||||
|
// skip taints that have effect PreferNoSchedule, since it is for priorities
|
||||||
|
if taint.Effect == api.TaintEffectPreferNoSchedule {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !api.TaintToleratedByTolerations(taint, tolerations) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -2358,3 +2358,286 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPodToleratesTaints(t *testing.T) {
|
||||||
|
podTolerateTaintsTests := []struct {
|
||||||
|
pod *api.Pod
|
||||||
|
node api.Node
|
||||||
|
fits bool
|
||||||
|
test string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"value": "user1",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: false,
|
||||||
|
test: "a pod having no tolerations can't be scheduled onto a node with nonempty taints",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod1",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"value": "user1",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod1:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"value": "user1",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: true,
|
||||||
|
test: "a pod which can be scheduled on a dedicated node assgined to user1 with effect NoSchedule",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod2",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"operator": "Equal",
|
||||||
|
"value": "user2",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod2:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"value": "user1",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: false,
|
||||||
|
test: "a pod which can't be scheduled on a dedicated node assgined to user2 with effect NoSchedule",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod2",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "foo",
|
||||||
|
"operator": "Exists",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod2:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "foo",
|
||||||
|
"value": "bar",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: true,
|
||||||
|
test: "a pod can be scheduled onto the node, with a toleration uses operator Exists that tolerates the taints on the node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod2",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"operator": "Equal",
|
||||||
|
"value": "user2",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}, {
|
||||||
|
"key": "foo",
|
||||||
|
"operator": "Exists",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod2:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"value": "user2",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}, {
|
||||||
|
"key": "foo",
|
||||||
|
"value": "bar",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: true,
|
||||||
|
test: "a pod has multiple tolerations, node has multiple taints, all the taints are tolerated, pod can be scheduled onto the node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod2",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "foo",
|
||||||
|
"operator": "Equal",
|
||||||
|
"value": "bar",
|
||||||
|
"effect": "PreferNoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod2:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "foo",
|
||||||
|
"value": "bar",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: false,
|
||||||
|
test: "a pod has a toleration that keys and values match the taint on the node, but (non-empty) effect doesn't match, " +
|
||||||
|
"can't be scheduled onto the node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod2",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "foo",
|
||||||
|
"operator": "Equal",
|
||||||
|
"value": "bar"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod2:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "foo",
|
||||||
|
"value": "bar",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: true,
|
||||||
|
test: "The pod has a toleration that keys and values match the taint on the node, the effect of toleration is empty, " +
|
||||||
|
"and the effect of taint is NoSchedule. Pod can be scheduled onto the node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod2",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"operator": "Equal",
|
||||||
|
"value": "user2",
|
||||||
|
"effect": "NoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{Image: "pod2:V1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: `
|
||||||
|
[{
|
||||||
|
"key": "dedicated",
|
||||||
|
"value": "user1",
|
||||||
|
"effect": "PreferNoSchedule"
|
||||||
|
}]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fits: true,
|
||||||
|
test: "The pod has a toleration that key and value don't match the taint on the node, " +
|
||||||
|
"but the effect of taint on node is PreferNochedule. Pod can be shceduled onto the node",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range podTolerateTaintsTests {
|
||||||
|
tolerationMatch := TolerationMatch{FakeNodeInfo(test.node)}
|
||||||
|
nodeInfo := schedulercache.NewNodeInfo()
|
||||||
|
nodeInfo.SetNode(&test.node)
|
||||||
|
fits, err := tolerationMatch.PodToleratesNodeTaints(test.pod, nodeInfo)
|
||||||
|
if fits == false && !reflect.DeepEqual(err, ErrTaintsTolerationsNotMatch) {
|
||||||
|
t.Errorf("%s, unexpected error: %v", test.test, err)
|
||||||
|
}
|
||||||
|
if fits != test.fits {
|
||||||
|
t.Errorf("%s, expected: %v got %v", test.test, test.fits, fits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
110
plugin/pkg/scheduler/algorithm/priorities/taint_toleration.go
Normal file
110
plugin/pkg/scheduler/algorithm/priorities/taint_toleration.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
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 priorities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
|
||||||
|
schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
|
||||||
|
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeTaints hold the node lister
|
||||||
|
type TaintToleration struct {
|
||||||
|
nodeLister algorithm.NodeLister
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTaintTolerationPriority
|
||||||
|
func NewTaintTolerationPriority(nodeLister algorithm.NodeLister) algorithm.PriorityFunction {
|
||||||
|
taintToleration := &TaintToleration{
|
||||||
|
nodeLister: nodeLister,
|
||||||
|
}
|
||||||
|
return taintToleration.ComputeTaintTolerationPriority
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountIntolerableTaintsPreferNoSchedule gives the count of intolerable taints of a pod with effect PreferNoSchedule
|
||||||
|
func countIntolerableTaintsPreferNoSchedule(taints []api.Taint, tolerations []api.Toleration) (intolerableTaints int) {
|
||||||
|
for _, taint := range taints {
|
||||||
|
// check only on taints that have effect PreferNoSchedule
|
||||||
|
if taint.Effect != api.TaintEffectPreferNoSchedule {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !api.TaintToleratedByTolerations(taint, tolerations) {
|
||||||
|
intolerableTaints++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAllTolerationEffectPreferNoSchedule gets the list of all Toleration with Effect PreferNoSchedule
|
||||||
|
func getAllTolerationPreferNoSchedule(tolerations []api.Toleration) (tolerationList []api.Toleration) {
|
||||||
|
for _, toleration := range tolerations {
|
||||||
|
if len(toleration.Effect) == 0 || toleration.Effect == api.TaintEffectPreferNoSchedule {
|
||||||
|
tolerationList = append(tolerationList, toleration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeTaintTolerationPriority prepares the priority list for all the nodes based on the number of intolerable taints on the node
|
||||||
|
func (s *TaintToleration) ComputeTaintTolerationPriority(pod *api.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodeLister algorithm.NodeLister) (schedulerapi.HostPriorityList, error) {
|
||||||
|
// counts hold the count of intolerable taints of a pod for a given node
|
||||||
|
counts := make(map[string]int)
|
||||||
|
|
||||||
|
// the max value of counts
|
||||||
|
var maxCount int
|
||||||
|
|
||||||
|
nodes, err := nodeLister.List()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tolerations, err := api.GetTolerationsFromPodAnnotations(pod.Annotations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Fetch a list of all toleration with effect PreferNoSchedule
|
||||||
|
tolerationList := getAllTolerationPreferNoSchedule(tolerations)
|
||||||
|
|
||||||
|
// calculate the intolerable taints for all the nodes
|
||||||
|
for _, node := range nodes.Items {
|
||||||
|
taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
count := countIntolerableTaintsPreferNoSchedule(taints, tolerationList)
|
||||||
|
counts[node.Name] = count
|
||||||
|
if count > maxCount {
|
||||||
|
maxCount = count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The maximum priority value to give to a node
|
||||||
|
// Priority values range from 0 - maxPriority
|
||||||
|
const maxPriority = 10
|
||||||
|
result := []schedulerapi.HostPriority{}
|
||||||
|
for _, node := range nodes.Items {
|
||||||
|
fScore := float64(maxPriority)
|
||||||
|
if maxCount > 0 {
|
||||||
|
fScore = (1.0 - float64(counts[node.Name])/float64(maxCount)) * 10
|
||||||
|
}
|
||||||
|
result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: int(fScore)})
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
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 priorities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
|
||||||
|
schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
|
||||||
|
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nodeWithTaints(nodeName string, taints []api.Taint) api.Node {
|
||||||
|
taintsData, _ := json.Marshal(taints)
|
||||||
|
return api.Node{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: nodeName,
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TaintsAnnotationKey: string(taintsData),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func podWithTolerations(tolerations []api.Toleration) *api.Pod {
|
||||||
|
tolerationData, _ := json.Marshal(tolerations)
|
||||||
|
return &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
api.TolerationsAnnotationKey: string(tolerationData),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will create a set of nodes and pods and test the priority
|
||||||
|
// Nodes with zero,one,two,three,four and hundred taints are created
|
||||||
|
// Pods with zero,one,two,three,four and hundred tolerations are created
|
||||||
|
|
||||||
|
func TestTaintAndToleration(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
pod *api.Pod
|
||||||
|
nodes []api.Node
|
||||||
|
expectedList schedulerapi.HostPriorityList
|
||||||
|
test string
|
||||||
|
}{
|
||||||
|
// basic test case
|
||||||
|
{
|
||||||
|
test: "node with taints tolerated by the pod, gets a higher score than those node with intolerable taints",
|
||||||
|
pod: podWithTolerations([]api.Toleration{{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: api.TolerationOpEqual,
|
||||||
|
Value: "bar",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}}),
|
||||||
|
nodes: []api.Node{
|
||||||
|
nodeWithTaints("nodeA", []api.Taint{{
|
||||||
|
Key: "foo",
|
||||||
|
Value: "bar",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}}),
|
||||||
|
nodeWithTaints("nodeB", []api.Taint{{
|
||||||
|
Key: "foo",
|
||||||
|
Value: "blah",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}}),
|
||||||
|
},
|
||||||
|
expectedList: []schedulerapi.HostPriority{
|
||||||
|
{Host: "nodeA", Score: 10},
|
||||||
|
{Host: "nodeB", Score: 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// the count of taints that are tolerated by pod, does not matter.
|
||||||
|
{
|
||||||
|
test: "the nodes that all of their taints are tolerated by the pod, get the same score, no matter how many tolerable taints a node has",
|
||||||
|
pod: podWithTolerations([]api.Toleration{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Operator: api.TolerationOpEqual,
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}, {
|
||||||
|
Key: "disk-type",
|
||||||
|
Operator: api.TolerationOpEqual,
|
||||||
|
Value: "ssd",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nodes: []api.Node{
|
||||||
|
nodeWithTaints("nodeA", []api.Taint{}),
|
||||||
|
nodeWithTaints("nodeB", []api.Taint{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nodeWithTaints("nodeC", []api.Taint{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}, {
|
||||||
|
Key: "disk-type",
|
||||||
|
Value: "ssd",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
expectedList: []schedulerapi.HostPriority{
|
||||||
|
{Host: "nodeA", Score: 10},
|
||||||
|
{Host: "nodeB", Score: 10},
|
||||||
|
{Host: "nodeC", Score: 10},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// the count of taints on a node that are not tolerated by pod, matters.
|
||||||
|
{
|
||||||
|
test: "the more intolerable taints a node has, the lower score it gets.",
|
||||||
|
pod: podWithTolerations([]api.Toleration{{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: api.TolerationOpEqual,
|
||||||
|
Value: "bar",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}}),
|
||||||
|
nodes: []api.Node{
|
||||||
|
nodeWithTaints("nodeA", []api.Taint{}),
|
||||||
|
nodeWithTaints("nodeB", []api.Taint{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nodeWithTaints("nodeC", []api.Taint{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}, {
|
||||||
|
Key: "disk-type",
|
||||||
|
Value: "ssd",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
expectedList: []schedulerapi.HostPriority{
|
||||||
|
{Host: "nodeA", Score: 10},
|
||||||
|
{Host: "nodeB", Score: 5},
|
||||||
|
{Host: "nodeC", Score: 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// taints-tolerations priority only takes care about the taints and tolerations that have effect PreferNoSchedule
|
||||||
|
{
|
||||||
|
test: "only taints and tolerations that have effect PreferNoSchedule are checked by taints-tolerations priority function",
|
||||||
|
pod: podWithTolerations([]api.Toleration{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Operator: api.TolerationOpEqual,
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectNoSchedule,
|
||||||
|
}, {
|
||||||
|
Key: "disk-type",
|
||||||
|
Operator: api.TolerationOpEqual,
|
||||||
|
Value: "ssd",
|
||||||
|
Effect: api.TaintEffectNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nodes: []api.Node{
|
||||||
|
nodeWithTaints("nodeA", []api.Taint{}),
|
||||||
|
nodeWithTaints("nodeB", []api.Taint{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nodeWithTaints("nodeC", []api.Taint{
|
||||||
|
{
|
||||||
|
Key: "cpu-type",
|
||||||
|
Value: "arm64",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
}, {
|
||||||
|
Key: "disk-type",
|
||||||
|
Value: "ssd",
|
||||||
|
Effect: api.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
expectedList: []schedulerapi.HostPriority{
|
||||||
|
{Host: "nodeA", Score: 10},
|
||||||
|
{Host: "nodeB", Score: 10},
|
||||||
|
{Host: "nodeC", Score: 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
nodeNameToInfo := schedulercache.CreateNodeNameToInfoMap([]*api.Pod{{}})
|
||||||
|
taintToleration := TaintToleration{nodeLister: algorithm.FakeNodeLister(api.NodeList{Items: test.nodes})}
|
||||||
|
list, err := taintToleration.ComputeTaintTolerationPriority(
|
||||||
|
test.pod,
|
||||||
|
nodeNameToInfo,
|
||||||
|
algorithm.FakeNodeLister(api.NodeList{Items: test.nodes}))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s, unexpected error: %v", test.test, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(test.expectedList, list) {
|
||||||
|
t.Errorf("%s,\nexpected:\n\t%+v,\ngot:\n\t%+v", test.test, test.expectedList, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -145,6 +145,14 @@ func defaultPredicates() sets.String {
|
|||||||
// GeneralPredicates are the predicates that are enforced by all Kubernetes components
|
// GeneralPredicates are the predicates that are enforced by all Kubernetes components
|
||||||
// (e.g. kubelet and all schedulers)
|
// (e.g. kubelet and all schedulers)
|
||||||
factory.RegisterFitPredicate("GeneralPredicates", predicates.GeneralPredicates),
|
factory.RegisterFitPredicate("GeneralPredicates", predicates.GeneralPredicates),
|
||||||
|
|
||||||
|
// Fit is determined based on whether a pod can tolerate all of the node's taints
|
||||||
|
factory.RegisterFitPredicateFactory(
|
||||||
|
"PodToleratesNodeTaints",
|
||||||
|
func(args factory.PluginFactoryArgs) algorithm.FitPredicate {
|
||||||
|
return predicates.NewTolerationMatchPredicate(args.NodeInfo)
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,5 +181,14 @@ func defaultPriorities() sets.String {
|
|||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
factory.RegisterPriorityConfigFactory(
|
||||||
|
"TaintTolerationPriority",
|
||||||
|
factory.PriorityConfigFactory{
|
||||||
|
Function: func(args factory.PluginFactoryArgs) algorithm.PriorityFunction {
|
||||||
|
return priorities.NewTaintTolerationPriority(args.NodeLister)
|
||||||
|
},
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
pkgutil "k8s.io/kubernetes/pkg/util"
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
"k8s.io/kubernetes/pkg/util/wait"
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
@ -1283,6 +1284,39 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
framework.KubeDescribe("Kubectl taint", func() {
|
||||||
|
It("should update the taint on a node", func() {
|
||||||
|
taintName := fmt.Sprintf("kubernetes.io/e2e-taint-key-%s", string(pkgutil.NewUUID()))
|
||||||
|
taintValue := "testing-taint-value"
|
||||||
|
taintEffect := fmt.Sprintf("%s", api.TaintEffectNoSchedule)
|
||||||
|
|
||||||
|
nodes, err := c.Nodes().List(api.ListOptions{})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
node := nodes.Items[0]
|
||||||
|
nodeName := node.Name
|
||||||
|
|
||||||
|
By("adding the taint " + taintName + " with value " + taintValue + " and taint effect " + taintEffect + " to a node")
|
||||||
|
framework.RunKubectlOrDie("taint", "nodes", nodeName, taintName+"="+taintValue+":"+taintEffect)
|
||||||
|
By("verifying the node has the taint " + taintName + " with the value " + taintValue)
|
||||||
|
output := framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
requiredStrings := [][]string{
|
||||||
|
{"Name:", nodeName},
|
||||||
|
{"Taints:"},
|
||||||
|
{taintName + "=" + taintValue + ":" + taintEffect},
|
||||||
|
}
|
||||||
|
checkOutput(output, requiredStrings)
|
||||||
|
|
||||||
|
By("removing the taint " + taintName + " of a node")
|
||||||
|
framework.RunKubectlOrDie("taint", "nodes", nodeName, taintName+"-")
|
||||||
|
By("verifying the node doesn't have the taint " + taintName)
|
||||||
|
output = framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
if strings.Contains(output, taintName) {
|
||||||
|
framework.Failf("Failed removing taint " + taintName + " of the node " + nodeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Checks whether the output split by line contains the required elements.
|
// Checks whether the output split by line contains the required elements.
|
||||||
|
@ -19,6 +19,7 @@ package e2e
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
@ -1280,4 +1281,250 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 1. Run a pod to get an available node, then delete the pod
|
||||||
|
// 2. Taint the node with a random taint
|
||||||
|
// 3. Try to relaunch the pod with tolerations tolerate the taints on node,
|
||||||
|
// and the pod's nodeName specified to the name of node found in step 1
|
||||||
|
It("validates that taints-tolerations is respected if matching", func() {
|
||||||
|
// launch a pod to find a node which can launch a pod. We intentionally do
|
||||||
|
// not just take the node list and choose the first of them. Depending on the
|
||||||
|
// cluster and the scheduler it might be that a "normal" pod cannot be
|
||||||
|
// scheduled onto it.
|
||||||
|
By("Trying to launch a pod without a toleration to get a node which can launch it.")
|
||||||
|
podName := "without-toleration"
|
||||||
|
_, err := c.Pods(ns).Create(&api.Pod{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: podName,
|
||||||
|
Image: "gcr.io/google_containers/pause-amd64:3.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
framework.ExpectNoError(framework.WaitForPodRunningInNamespace(c, podName, ns))
|
||||||
|
pod, err := c.Pods(ns).Get(podName)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
nodeName := pod.Spec.NodeName
|
||||||
|
err = c.Pods(ns).Delete(podName, api.NewDeleteOptions(0))
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
By("Trying to apply a random taint on the found node.")
|
||||||
|
taintName := fmt.Sprintf("kubernetes.io/e2e-taint-key-%s", string(util.NewUUID()))
|
||||||
|
taintValue := "testing-taint-value"
|
||||||
|
taintEffect := string(api.TaintEffectNoSchedule)
|
||||||
|
framework.RunKubectlOrDie("taint", "nodes", nodeName, taintName+"="+taintValue+":"+taintEffect)
|
||||||
|
By("verifying the node has the taint " + taintName + " with the value " + taintValue)
|
||||||
|
output := framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
requiredStrings := [][]string{
|
||||||
|
{"Name:", nodeName},
|
||||||
|
{"Taints:"},
|
||||||
|
{taintName, taintValue, taintEffect},
|
||||||
|
}
|
||||||
|
checkOutput(output, requiredStrings)
|
||||||
|
|
||||||
|
By("Trying to apply a random label on the found node.")
|
||||||
|
labelKey := fmt.Sprintf("kubernetes.io/e2e-label-key-%s", string(util.NewUUID()))
|
||||||
|
labelValue := "testing-label-value"
|
||||||
|
framework.RunKubectlOrDie("label", "nodes", nodeName, labelKey+"="+labelValue)
|
||||||
|
By("verifying the node has the label " + labelKey + " with the value " + labelValue)
|
||||||
|
labelOutput := framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
labelOutputRequiredStrings := [][]string{
|
||||||
|
{"Name:", nodeName},
|
||||||
|
{"Labels:"},
|
||||||
|
{labelKey + "=" + labelValue},
|
||||||
|
}
|
||||||
|
checkOutput(labelOutput, labelOutputRequiredStrings)
|
||||||
|
|
||||||
|
By("Trying to relaunch the pod, now with tolerations.")
|
||||||
|
tolerationPodName := "with-tolerations"
|
||||||
|
_, err = c.Pods(ns).Create(&api.Pod{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: tolerationPodName,
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"scheduler.alpha.kubernetes.io/tolerations": `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "` + taintName + `",
|
||||||
|
"value": "` + taintValue + `",
|
||||||
|
"effect": "` + taintEffect + `"
|
||||||
|
}
|
||||||
|
]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
NodeSelector: map[string]string{labelKey: labelValue},
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: tolerationPodName,
|
||||||
|
Image: "gcr.io/google_containers/pause-amd64:3.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
defer c.Pods(ns).Delete(tolerationPodName, api.NewDeleteOptions(0))
|
||||||
|
|
||||||
|
// check that pod got scheduled. We intentionally DO NOT check that the
|
||||||
|
// pod is running because this will create a race condition with the
|
||||||
|
// kubelet and the scheduler: the scheduler might have scheduled a pod
|
||||||
|
// already when the kubelet does not know about its new taint yet. The
|
||||||
|
// kubelet will then refuse to launch the pod.
|
||||||
|
framework.ExpectNoError(framework.WaitForPodNotPending(c, ns, tolerationPodName))
|
||||||
|
deployedPod, err := c.Pods(ns).Get(tolerationPodName)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
Expect(deployedPod.Spec.NodeName).To(Equal(nodeName))
|
||||||
|
|
||||||
|
By("removing the taint " + taintName + " off the node " + nodeName)
|
||||||
|
framework.RunKubectlOrDie("taint", "nodes", nodeName, taintName+"-")
|
||||||
|
By("verifying the node doesn't have the taint " + taintName)
|
||||||
|
output = framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
if strings.Contains(output, taintName) {
|
||||||
|
framework.Failf("Failed removing taint " + taintName + " of the node " + nodeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
By("removing the label " + labelKey + " off the node " + nodeName)
|
||||||
|
framework.RunKubectlOrDie("label", "nodes", nodeName, labelKey+"-")
|
||||||
|
By("verifying the node doesn't have the label " + labelKey)
|
||||||
|
output = framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
if strings.Contains(output, labelKey) {
|
||||||
|
framework.Failf("Failed removing label " + labelKey + " of the node " + nodeName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 1. Run a pod to get an available node, then delete the pod
|
||||||
|
// 2. Taint the node with a random taint
|
||||||
|
// 3. Try to relaunch the pod still no tolerations,
|
||||||
|
// and the pod's nodeName specified to the name of node found in step 1
|
||||||
|
It("validates that taints-tolerations is respected if not matching", func() {
|
||||||
|
// launch a pod to find a node which can launch a pod. We intentionally do
|
||||||
|
// not just take the node list and choose the first of them. Depending on the
|
||||||
|
// cluster and the scheduler it might be that a "normal" pod cannot be
|
||||||
|
// scheduled onto it.
|
||||||
|
By("Trying to launch a pod without a toleration to get a node which can launch it.")
|
||||||
|
podName := "without-toleration"
|
||||||
|
_, err := c.Pods(ns).Create(&api.Pod{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: podName,
|
||||||
|
Image: "gcr.io/google_containers/pause-amd64:3.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
framework.ExpectNoError(framework.WaitForPodRunningInNamespace(c, podName, ns))
|
||||||
|
pod, err := c.Pods(ns).Get(podName)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
nodeName := pod.Spec.NodeName
|
||||||
|
err = c.Pods(ns).Delete(podName, api.NewDeleteOptions(0))
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
By("Trying to apply a random taint on the found node.")
|
||||||
|
taintName := fmt.Sprintf("kubernetes.io/e2e-taint-key-%s", string(util.NewUUID()))
|
||||||
|
taintValue := "testing-taint-value"
|
||||||
|
taintEffect := string(api.TaintEffectNoSchedule)
|
||||||
|
framework.RunKubectlOrDie("taint", "nodes", nodeName, taintName+"="+taintValue+":"+taintEffect)
|
||||||
|
By("verifying the node has the taint " + taintName + " with the value " + taintValue)
|
||||||
|
output := framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
requiredStrings := [][]string{
|
||||||
|
{"Name:", nodeName},
|
||||||
|
{"Taints:"},
|
||||||
|
{taintName, taintValue, taintEffect},
|
||||||
|
}
|
||||||
|
checkOutput(output, requiredStrings)
|
||||||
|
|
||||||
|
By("Trying to apply a random label on the found node.")
|
||||||
|
labelKey := fmt.Sprintf("kubernetes.io/e2e-label-key-%s", string(util.NewUUID()))
|
||||||
|
labelValue := "testing-label-value"
|
||||||
|
framework.RunKubectlOrDie("label", "nodes", nodeName, labelKey+"="+labelValue)
|
||||||
|
By("verifying the node has the label " + labelKey + " with the value " + labelValue)
|
||||||
|
labelOutput := framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
labelOutputRequiredStrings := [][]string{
|
||||||
|
{"Name:", nodeName},
|
||||||
|
{"Labels:"},
|
||||||
|
{labelKey + "=" + labelValue},
|
||||||
|
}
|
||||||
|
checkOutput(labelOutput, labelOutputRequiredStrings)
|
||||||
|
|
||||||
|
By("Trying to relaunch the pod, still no tolerations.")
|
||||||
|
podNameNoTolerations := "still-no-tolerations"
|
||||||
|
podNoTolerations := api.Pod{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: podNameNoTolerations,
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
NodeSelector: map[string]string{labelKey: labelValue},
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: podNameNoTolerations,
|
||||||
|
Image: "gcr.io/google_containers/pause-amd64:3.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = c.Pods(ns).Create(&podNoTolerations)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
// Wait a bit to allow scheduler to do its thing
|
||||||
|
// TODO: this is brittle; there's no guarantee the scheduler will have run in 10 seconds.
|
||||||
|
framework.Logf("Sleeping 10 seconds and crossing our fingers that scheduler will run in that time.")
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
|
||||||
|
verifyResult(c, podNameNoTolerations, ns)
|
||||||
|
cleanupPods(c, ns)
|
||||||
|
|
||||||
|
By("removing the taint " + taintName + " off the node " + nodeName)
|
||||||
|
framework.RunKubectlOrDie("taint", "nodes", nodeName, taintName+"-")
|
||||||
|
By("verifying the node doesn't have the taint " + taintName)
|
||||||
|
output = framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
if strings.Contains(output, taintName) {
|
||||||
|
framework.Failf("Failed removing taint " + taintName + " of the node " + nodeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
By("Trying to relaunch the same.")
|
||||||
|
_, err = c.Pods(ns).Create(&podNoTolerations)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
defer c.Pods(ns).Delete(podNameNoTolerations, api.NewDeleteOptions(0))
|
||||||
|
|
||||||
|
// check that pod got scheduled. We intentionally DO NOT check that the
|
||||||
|
// pod is running because this will create a race condition with the
|
||||||
|
// kubelet and the scheduler: the scheduler might have scheduled a pod
|
||||||
|
// already when the kubelet does not know about its new taint yet. The
|
||||||
|
// kubelet will then refuse to launch the pod.
|
||||||
|
framework.ExpectNoError(framework.WaitForPodNotPending(c, ns, podNameNoTolerations))
|
||||||
|
deployedPod, err := c.Pods(ns).Get(podNameNoTolerations)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
Expect(deployedPod.Spec.NodeName).To(Equal(nodeName))
|
||||||
|
|
||||||
|
By("removing the label " + labelKey + " off the node " + nodeName)
|
||||||
|
framework.RunKubectlOrDie("label", "nodes", nodeName, labelKey+"-")
|
||||||
|
By("verifying the node doesn't have the label " + labelKey)
|
||||||
|
output = framework.RunKubectlOrDie("describe", "node", nodeName)
|
||||||
|
if strings.Contains(output, labelKey) {
|
||||||
|
framework.Failf("Failed removing label " + labelKey + " of the node " + nodeName)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user