mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Add 'kubectl set image'
This commit is contained in:
parent
28333a0041
commit
4332472bde
@ -53,6 +53,7 @@ docs/man/man1/kubectl-rollout-undo.1
|
|||||||
docs/man/man1/kubectl-rollout.1
|
docs/man/man1/kubectl-rollout.1
|
||||||
docs/man/man1/kubectl-run.1
|
docs/man/man1/kubectl-run.1
|
||||||
docs/man/man1/kubectl-scale.1
|
docs/man/man1/kubectl-scale.1
|
||||||
|
docs/man/man1/kubectl-set-image.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-taint.1
|
||||||
@ -109,6 +110,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_set_image.md
|
||||||
docs/user-guide/kubectl/kubectl_taint.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
|
||||||
|
@ -478,10 +478,78 @@ _kubectl_get()
|
|||||||
noun_aliases+=("thirdpartyresources")
|
noun_aliases+=("thirdpartyresources")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_kubectl_set_image()
|
||||||
|
{
|
||||||
|
last_command="kubectl_set_image"
|
||||||
|
commands=()
|
||||||
|
|
||||||
|
flags=()
|
||||||
|
two_word_flags=()
|
||||||
|
flags_with_completion=()
|
||||||
|
flags_completion=()
|
||||||
|
|
||||||
|
flags+=("--all")
|
||||||
|
flags+=("--filename=")
|
||||||
|
flags_with_completion+=("--filename")
|
||||||
|
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
|
||||||
|
two_word_flags+=("-f")
|
||||||
|
flags_with_completion+=("-f")
|
||||||
|
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
|
||||||
|
flags+=("--local")
|
||||||
|
flags+=("--no-headers")
|
||||||
|
flags+=("--output=")
|
||||||
|
two_word_flags+=("-o")
|
||||||
|
flags+=("--output-version=")
|
||||||
|
flags+=("--record")
|
||||||
|
flags+=("--recursive")
|
||||||
|
flags+=("-R")
|
||||||
|
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+=("--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=()
|
||||||
|
noun_aliases=()
|
||||||
|
}
|
||||||
|
|
||||||
_kubectl_set()
|
_kubectl_set()
|
||||||
{
|
{
|
||||||
last_command="kubectl_set"
|
last_command="kubectl_set"
|
||||||
commands=()
|
commands=()
|
||||||
|
commands+=("image")
|
||||||
|
|
||||||
flags=()
|
flags=()
|
||||||
two_word_flags=()
|
two_word_flags=()
|
||||||
|
@ -27,7 +27,7 @@ An autoscaler can automatically increase or decrease number of pods deployed wit
|
|||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-dry\-run\fP=false
|
\fB\-\-dry\-run\fP=false
|
||||||
If true, only print the object that would be sent, without creating it.
|
If true, only print the object that would be sent, without sending it.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-f\fP, \fB\-\-filename\fP=[]
|
\fB\-f\fP, \fB\-\-filename\fP=[]
|
||||||
|
@ -40,7 +40,7 @@ Possible resources include (case insensitive):
|
|||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-dry\-run\fP=false
|
\fB\-\-dry\-run\fP=false
|
||||||
If true, only print the object that would be sent, without creating it.
|
If true, only print the object that would be sent, without sending it.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-external\-ip\fP=""
|
\fB\-\-external\-ip\fP=""
|
||||||
|
@ -32,7 +32,7 @@ existing replication controller and overwrite at least one (common) label in its
|
|||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-dry\-run\fP=false
|
\fB\-\-dry\-run\fP=false
|
||||||
If true, print out the changes that would be made, but don't actually make them.
|
If true, only print the object that would be sent, without sending it.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-f\fP, \fB\-\-filename\fP=[]
|
\fB\-f\fP, \fB\-\-filename\fP=[]
|
||||||
|
206
docs/man/man1/kubectl-set-image.1
Normal file
206
docs/man/man1/kubectl-set-image.1
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" ""
|
||||||
|
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
.PP
|
||||||
|
kubectl set image \- Update image of a pod template
|
||||||
|
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.PP
|
||||||
|
\fBkubectl set image\fP [OPTIONS]
|
||||||
|
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
Update existing container image(s) of resources.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
Possible resources include (case insensitive):
|
||||||
|
pod (po), replicationcontroller (rc), deployment, daemonset (ds), job, replicaset (rs)
|
||||||
|
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.PP
|
||||||
|
\fB\-\-all\fP=false
|
||||||
|
select all resources in the namespace of the specified resource types
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-f\fP, \fB\-\-filename\fP=[]
|
||||||
|
Filename, directory, or URL to a file identifying the resource to get from a server.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-local\fP=false
|
||||||
|
If true, set image will NOT contact api\-server but run locally.
|
||||||
|
|
||||||
|
.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\-\-record\fP=false
|
||||||
|
Record current kubectl command in the resource annotation.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-R\fP, \fB\-\-recursive\fP=false
|
||||||
|
If true, process directory recursively.
|
||||||
|
|
||||||
|
.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]].
|
||||||
|
|
||||||
|
|
||||||
|
.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
|
||||||
|
# Set a deployment's nginx container image to 'nginx:1.9.1', and its busybox container image to 'busybox'.
|
||||||
|
kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
|
||||||
|
|
||||||
|
# Update all deployments' and rc's nginx container's image to 'nginx:1.9.1'
|
||||||
|
kubectl set image deployments,rc nginx=nginx:1.9.1 \-\-all
|
||||||
|
|
||||||
|
# Update image of all containers of daemonset abc to 'nginx:1.9.1'
|
||||||
|
kubectl set image daemonset abc *=nginx:1.9.1
|
||||||
|
|
||||||
|
# Print result (in yaml format) of updating nginx container image from local file, without hitting the server
|
||||||
|
kubectl set image \-f path/to/file.yaml nginx=nginx:1.9.1 \-\-local \-o yaml
|
||||||
|
|
||||||
|
.fi
|
||||||
|
.RE
|
||||||
|
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.PP
|
||||||
|
\fBkubectl\-set(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!
|
@ -119,7 +119,7 @@ These commands help you make changes to existing application resources.
|
|||||||
|
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.PP
|
.PP
|
||||||
\fBkubectl(1)\fP,
|
\fBkubectl(1)\fP, \fBkubectl\-set\-image(1)\fP,
|
||||||
|
|
||||||
|
|
||||||
.SH HISTORY
|
.SH HISTORY
|
||||||
|
@ -62,7 +62,7 @@ kubectl autoscale rc foo --max=5 --cpu-percent=80
|
|||||||
|
|
||||||
```
|
```
|
||||||
--cpu-percent=-1: The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, the server will apply a default value.
|
--cpu-percent=-1: The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, the server will apply a default value.
|
||||||
--dry-run[=false]: If true, only print the object that would be sent, without creating it.
|
--dry-run[=false]: If true, only print the object that would be sent, without sending it.
|
||||||
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to autoscale.
|
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to autoscale.
|
||||||
--generator="horizontalpodautoscaler/v1beta1": The name of the API generator to use. Currently there is only 1 generator.
|
--generator="horizontalpodautoscaler/v1beta1": The name of the API generator to use. Currently there is only 1 generator.
|
||||||
--include-extended-apis[=true]: If true, include definitions of new APIs via calls to the API server. [default true]
|
--include-extended-apis[=true]: If true, include definitions of new APIs via calls to the API server. [default true]
|
||||||
@ -113,7 +113,7 @@ kubectl autoscale rc foo --max=5 --cpu-percent=80
|
|||||||
|
|
||||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 30-Mar-2016
|
###### Auto generated by spf13/cobra on 13-May-2016
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
[]()
|
[]()
|
||||||
|
@ -85,7 +85,7 @@ kubectl expose deployment nginx --port=80 --target-port=8000
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
--dry-run[=false]: If true, only print the object that would be sent, without creating it.
|
--dry-run[=false]: If true, only print the object that would be sent, without sending it.
|
||||||
--external-ip="": Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.
|
--external-ip="": Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.
|
||||||
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to expose a service
|
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to expose a service
|
||||||
--generator="service/v2": The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'.
|
--generator="service/v2": The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'.
|
||||||
@ -143,7 +143,7 @@ kubectl expose deployment nginx --port=80 --target-port=8000
|
|||||||
|
|
||||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 11-May-2016
|
###### Auto generated by spf13/cobra on 13-May-2016
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
[]()
|
[]()
|
||||||
|
@ -75,7 +75,7 @@ kubectl rolling-update frontend-v1 frontend-v2 --rollback
|
|||||||
```
|
```
|
||||||
--container="": Container name which will have its image upgraded. Only relevant when --image is specified, ignored otherwise. Required when using --image on a multi-container pod
|
--container="": Container name which will have its image upgraded. Only relevant when --image is specified, ignored otherwise. Required when using --image on a multi-container pod
|
||||||
--deployment-label-key="deployment": The key to use to differentiate between two different controllers, default 'deployment'. Only relevant when --image is specified, ignored otherwise
|
--deployment-label-key="deployment": The key to use to differentiate between two different controllers, default 'deployment'. Only relevant when --image is specified, ignored otherwise
|
||||||
--dry-run[=false]: If true, print out the changes that would be made, but don't actually make them.
|
--dry-run[=false]: If true, only print the object that would be sent, without sending it.
|
||||||
-f, --filename=[]: Filename or URL to file to use to create the new replication controller.
|
-f, --filename=[]: Filename or URL to file to use to create the new replication controller.
|
||||||
--image="": Image to use for upgrading the replication controller. Must be distinct from the existing image (either new image or new image tag). Can not be used with --filename/-f
|
--image="": Image to use for upgrading the replication controller. Must be distinct from the existing image (either new image or new image tag). Can not be used with --filename/-f
|
||||||
--image-pull-policy="": Explicit policy for when to pull container images. Required when --image is same as existing image, ignored otherwise.
|
--image-pull-policy="": Explicit policy for when to pull container images. Required when --image is same as existing image, ignored otherwise.
|
||||||
@ -127,7 +127,7 @@ kubectl rolling-update frontend-v1 frontend-v2 --rollback
|
|||||||
|
|
||||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 21-Apr-2016
|
###### Auto generated by spf13/cobra on 13-May-2016
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
[]()
|
[]()
|
||||||
|
@ -73,6 +73,7 @@ kubectl set SUBCOMMAND
|
|||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||||
|
* [kubectl set image](kubectl_set_image.md) - Update image of a pod template
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 10-May-2016
|
###### Auto generated by spf13/cobra on 10-May-2016
|
||||||
|
|
||||||
|
116
docs/user-guide/kubectl/kubectl_set_image.md
Normal file
116
docs/user-guide/kubectl/kubectl_set_image.md
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<!-- 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 set image
|
||||||
|
|
||||||
|
Update image of a pod template
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
|
||||||
|
Update existing container image(s) of resources.
|
||||||
|
|
||||||
|
Possible resources include (case insensitive):
|
||||||
|
pod (po), replicationcontroller (rc), deployment, daemonset (ds), job, replicaset (rs)
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
# Set a deployment's nginx container image to 'nginx:1.9.1', and its busybox container image to 'busybox'.
|
||||||
|
kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
|
||||||
|
|
||||||
|
# Update all deployments' and rc's nginx container's image to 'nginx:1.9.1'
|
||||||
|
kubectl set image deployments,rc nginx=nginx:1.9.1 --all
|
||||||
|
|
||||||
|
# Update image of all containers of daemonset abc to 'nginx:1.9.1'
|
||||||
|
kubectl set image daemonset abc *=nginx:1.9.1
|
||||||
|
|
||||||
|
# Print result (in yaml format) of updating nginx container image from local file, without hitting the server
|
||||||
|
kubectl set image -f path/to/file.yaml nginx=nginx:1.9.1 --local -o yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
--all[=false]: select all resources in the namespace of the specified resource types
|
||||||
|
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to get from a server.
|
||||||
|
--local[=false]: If true, set image will NOT contact api-server but run locally.
|
||||||
|
--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').
|
||||||
|
--record[=false]: Record current kubectl command in the resource annotation.
|
||||||
|
-R, --recursive[=false]: If true, process directory recursively.
|
||||||
|
-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].
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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 set](kubectl_set.md) - Set specific features on objects
|
||||||
|
|
||||||
|
###### Auto generated by spf13/cobra on 17-May-2016
|
||||||
|
|
||||||
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
|
[]()
|
||||||
|
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
@ -14,7 +14,7 @@ options:
|
|||||||
- name: dry-run
|
- name: dry-run
|
||||||
default_value: "false"
|
default_value: "false"
|
||||||
usage: |
|
usage: |
|
||||||
If true, only print the object that would be sent, without creating it.
|
If true, only print the object that would be sent, without sending it.
|
||||||
- name: filename
|
- name: filename
|
||||||
shorthand: f
|
shorthand: f
|
||||||
default_value: '[]'
|
default_value: '[]'
|
||||||
|
@ -21,7 +21,7 @@ options:
|
|||||||
- name: dry-run
|
- name: dry-run
|
||||||
default_value: "false"
|
default_value: "false"
|
||||||
usage: |
|
usage: |
|
||||||
If true, only print the object that would be sent, without creating it.
|
If true, only print the object that would be sent, without sending it.
|
||||||
- name: external-ip
|
- name: external-ip
|
||||||
usage: |
|
usage: |
|
||||||
Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.
|
Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.
|
||||||
|
@ -17,7 +17,7 @@ options:
|
|||||||
- name: dry-run
|
- name: dry-run
|
||||||
default_value: "false"
|
default_value: "false"
|
||||||
usage: |
|
usage: |
|
||||||
If true, print out the changes that would be made, but don't actually make them.
|
If true, only print the object that would be sent, without sending it.
|
||||||
- name: filename
|
- name: filename
|
||||||
shorthand: f
|
shorthand: f
|
||||||
default_value: '[]'
|
default_value: '[]'
|
||||||
|
@ -65,3 +65,4 @@ inherited_options:
|
|||||||
comma-separated list of pattern=N settings for file-filtered logging
|
comma-separated list of pattern=N settings for file-filtered logging
|
||||||
see_also:
|
see_also:
|
||||||
- kubectl
|
- kubectl
|
||||||
|
- image
|
||||||
|
@ -291,6 +291,7 @@ runTests() {
|
|||||||
secret_data=".data"
|
secret_data=".data"
|
||||||
secret_type=".type"
|
secret_type=".type"
|
||||||
deployment_image_field="(index .spec.template.spec.containers 0).image"
|
deployment_image_field="(index .spec.template.spec.containers 0).image"
|
||||||
|
deployment_second_image_field="(index .spec.template.spec.containers 1).image"
|
||||||
change_cause_annotation='.*kubernetes.io/change-cause.*'
|
change_cause_annotation='.*kubernetes.io/change-cause.*'
|
||||||
|
|
||||||
# Passing no arguments to create is an error
|
# Passing no arguments to create is an error
|
||||||
@ -1620,6 +1621,11 @@ __EOF__
|
|||||||
# Clean up
|
# Clean up
|
||||||
kubectl delete rc frontend "${kube_flags[@]}"
|
kubectl delete rc frontend "${kube_flags[@]}"
|
||||||
|
|
||||||
|
|
||||||
|
######################
|
||||||
|
# Deployments #
|
||||||
|
######################
|
||||||
|
|
||||||
### Auto scale deployment
|
### Auto scale deployment
|
||||||
# Pre-condition: no deployment exists
|
# Pre-condition: no deployment exists
|
||||||
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
@ -1670,6 +1676,39 @@ __EOF__
|
|||||||
# Clean up
|
# Clean up
|
||||||
kubectl delete deployment nginx-deployment "${kube_flags[@]}"
|
kubectl delete deployment nginx-deployment "${kube_flags[@]}"
|
||||||
|
|
||||||
|
### Set image of a deployment
|
||||||
|
# Pre-condition: no deployment exists
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
|
# Create a deployment
|
||||||
|
kubectl create -f hack/testdata/deployment-multicontainer.yaml "${kube_flags[@]}"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx-deployment:'
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_second_image_field}}:{{end}}" "${IMAGE_PERL}:"
|
||||||
|
# Set the deployment's image
|
||||||
|
kubectl set image deployment nginx-deployment nginx="${IMAGE_DEPLOYMENT_R2}" "${kube_flags[@]}"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_second_image_field}}:{{end}}" "${IMAGE_PERL}:"
|
||||||
|
# Set non-existing container should fail
|
||||||
|
! kubectl set image deployment nginx-deployment redis=redis "${kube_flags[@]}"
|
||||||
|
# Set image of deployments without specifying name
|
||||||
|
kubectl set image deployments --all nginx="${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]}"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_second_image_field}}:{{end}}" "${IMAGE_PERL}:"
|
||||||
|
# Set image of a deployment specified by file
|
||||||
|
kubectl set image -f hack/testdata/deployment-multicontainer.yaml nginx="${IMAGE_DEPLOYMENT_R2}" "${kube_flags[@]}"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_second_image_field}}:{{end}}" "${IMAGE_PERL}:"
|
||||||
|
# Set image of a local file without talking to the server
|
||||||
|
kubectl set image -f hack/testdata/deployment-multicontainer.yaml nginx="${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]}" --local -o yaml
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_second_image_field}}:{{end}}" "${IMAGE_PERL}:"
|
||||||
|
# Set image of all containers of the deployment
|
||||||
|
kubectl set image deployment nginx-deployment "*"="${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]}"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$deployment_second_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
|
||||||
|
# Clean up
|
||||||
|
kubectl delete deployment nginx-deployment "${kube_flags[@]}"
|
||||||
|
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# Replica Sets #
|
# Replica Sets #
|
||||||
|
23
hack/testdata/deployment-multicontainer.yaml
vendored
Normal file
23
hack/testdata/deployment-multicontainer.yaml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
labels:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
name: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: gcr.io/google-containers/nginx:test-cmd
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
- name: perl
|
||||||
|
image: gcr.io/google-containers/perl
|
@ -148,22 +148,11 @@ func (o *AnnotateOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra
|
|||||||
|
|
||||||
// retrieves resource and annotation args from args
|
// retrieves resource and annotation args from args
|
||||||
// also checks args to verify that all resources are specified before annotations
|
// also checks args to verify that all resources are specified before annotations
|
||||||
annotationArgs := []string{}
|
resources, annotationArgs, err := cmdutil.GetResourcesAndPairs(args, "annotation")
|
||||||
metAnnotaionArg := false
|
if err != nil {
|
||||||
for _, s := range args {
|
return err
|
||||||
isAnnotation := strings.Contains(s, "=") || strings.HasSuffix(s, "-")
|
|
||||||
switch {
|
|
||||||
case !metAnnotaionArg && isAnnotation:
|
|
||||||
metAnnotaionArg = true
|
|
||||||
fallthrough
|
|
||||||
case metAnnotaionArg && isAnnotation:
|
|
||||||
annotationArgs = append(annotationArgs, s)
|
|
||||||
case !metAnnotaionArg && !isAnnotation:
|
|
||||||
o.resources = append(o.resources, s)
|
|
||||||
case metAnnotaionArg && !isAnnotation:
|
|
||||||
return fmt.Errorf("all resources must be specified before annotation changes: %s", s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
o.resources = resources
|
||||||
if len(o.resources) < 1 && len(o.filenames) == 0 {
|
if len(o.resources) < 1 && len(o.filenames) == 0 {
|
||||||
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||||
}
|
}
|
||||||
@ -277,34 +266,7 @@ func (o AnnotateOptions) RunAnnotate() error {
|
|||||||
|
|
||||||
// parseAnnotations retrieves new and remove annotations from annotation args
|
// parseAnnotations retrieves new and remove annotations from annotation args
|
||||||
func parseAnnotations(annotationArgs []string) (map[string]string, []string, error) {
|
func parseAnnotations(annotationArgs []string) (map[string]string, []string, error) {
|
||||||
var invalidBuf bytes.Buffer
|
return cmdutil.ParsePairs(annotationArgs, "annotation", true)
|
||||||
newAnnotations := map[string]string{}
|
|
||||||
removeAnnotations := []string{}
|
|
||||||
for _, annotationArg := range annotationArgs {
|
|
||||||
if strings.Index(annotationArg, "=") != -1 {
|
|
||||||
parts := strings.SplitN(annotationArg, "=", 2)
|
|
||||||
if len(parts) != 2 || len(parts[1]) == 0 {
|
|
||||||
if invalidBuf.Len() > 0 {
|
|
||||||
invalidBuf.WriteString(", ")
|
|
||||||
}
|
|
||||||
invalidBuf.WriteString(fmt.Sprintf(annotationArg))
|
|
||||||
} else {
|
|
||||||
newAnnotations[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
} else if strings.HasSuffix(annotationArg, "-") {
|
|
||||||
removeAnnotations = append(removeAnnotations, annotationArg[:len(annotationArg)-1])
|
|
||||||
} else {
|
|
||||||
if invalidBuf.Len() > 0 {
|
|
||||||
invalidBuf.WriteString(", ")
|
|
||||||
}
|
|
||||||
invalidBuf.WriteString(fmt.Sprintf(annotationArg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if invalidBuf.Len() > 0 {
|
|
||||||
return newAnnotations, removeAnnotations, fmt.Errorf("invalid annotation format: %s", invalidBuf.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return newAnnotations, removeAnnotations, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateAnnotations checks the format of annotation args and checks removed annotations aren't in the new annotations map
|
// validateAnnotations checks the format of annotation args and checks removed annotations aren't in the new annotations map
|
||||||
|
@ -68,7 +68,7 @@ func NewCmdAutoscale(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
cmd.MarkFlagRequired("max")
|
cmd.MarkFlagRequired("max")
|
||||||
cmd.Flags().Int("cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, the server will apply a default value."))
|
cmd.Flags().Int("cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, the server will apply a default value."))
|
||||||
cmd.Flags().String("name", "", "The name for the newly created object. If not specified, the name of the input resource will be used.")
|
cmd.Flags().String("name", "", "The name for the newly created object. If not specified, the name of the input resource will be used.")
|
||||||
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without creating it.")
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
usage := "Filename, directory, or URL to a file identifying the resource to autoscale."
|
usage := "Filename, directory, or URL to a file identifying the resource to autoscale."
|
||||||
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
||||||
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
||||||
@ -160,8 +160,7 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||||||
}
|
}
|
||||||
object = hpa.Object
|
object = hpa.Object
|
||||||
}
|
}
|
||||||
// TODO: extract this flag to a central location, when such a location exists.
|
if cmdutil.GetDryRunFlag(cmd) {
|
||||||
if cmdutil.GetFlagBool(cmd, "dry-run") {
|
|
||||||
return f.PrintObject(cmd, mapper, object, out)
|
return f.PrintObject(cmd, mapper, object, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ func CreateConfigMap(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, a
|
|||||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
StructuredGenerator: generator,
|
StructuredGenerator: generator,
|
||||||
DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
|
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func CreateNamespace(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, a
|
|||||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
StructuredGenerator: generator,
|
StructuredGenerator: generator,
|
||||||
DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
|
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ func CreateSecretGeneric(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comman
|
|||||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
StructuredGenerator: generator,
|
StructuredGenerator: generator,
|
||||||
DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
|
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -188,7 +188,7 @@ func CreateSecretDockerRegistry(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra
|
|||||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
StructuredGenerator: generator,
|
StructuredGenerator: generator,
|
||||||
DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
|
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func CreateServiceAccount(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comma
|
|||||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
StructuredGenerator: generator,
|
StructuredGenerator: generator,
|
||||||
DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
|
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,6 @@ func NewCmdExposeService(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().String("load-balancer-ip", "", "IP to assign to to the Load Balancer. If empty, an ephemeral IP will be created and used (cloud-provider specific).")
|
cmd.Flags().String("load-balancer-ip", "", "IP to assign to to the Load Balancer. If empty, an ephemeral IP will be created and used (cloud-provider specific).")
|
||||||
cmd.Flags().String("selector", "", "A label selector to use for this service. Only equality-based selector requirements are supported. If empty (the default) infer the selector from the replication controller or replica set.")
|
cmd.Flags().String("selector", "", "A label selector to use for this service. Only equality-based selector requirements are supported. If empty (the default) infer the selector from the replication controller or replica set.")
|
||||||
cmd.Flags().StringP("labels", "l", "", "Labels to apply to the service created by this call.")
|
cmd.Flags().StringP("labels", "l", "", "Labels to apply to the service created by this call.")
|
||||||
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without creating it.")
|
|
||||||
cmd.Flags().String("container-port", "", "Synonym for --target-port")
|
cmd.Flags().String("container-port", "", "Synonym for --target-port")
|
||||||
cmd.Flags().MarkDeprecated("container-port", "--container-port will be removed in the future, please use --target-port instead")
|
cmd.Flags().MarkDeprecated("container-port", "--container-port will be removed in the future, please use --target-port instead")
|
||||||
cmd.Flags().String("target-port", "", "Name or number for the port on the container that the service should direct traffic to. Optional.")
|
cmd.Flags().String("target-port", "", "Name or number for the port on the container that the service should direct traffic to. Optional.")
|
||||||
@ -121,6 +120,7 @@ func NewCmdExposeService(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
|
|
||||||
usage := "Filename, directory, or URL to a file identifying the resource to expose a service"
|
usage := "Filename, directory, or URL to a file identifying the resource to expose a service"
|
||||||
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
||||||
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
||||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
cmdutil.AddRecordFlag(cmd)
|
||||||
@ -256,8 +256,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.Refresh(object, true)
|
info.Refresh(object, true)
|
||||||
// TODO: extract this flag to a central location, when such a location exists.
|
if cmdutil.GetDryRunFlag(cmd) {
|
||||||
if cmdutil.GetFlagBool(cmd, "dry-run") {
|
|
||||||
return f.PrintObject(cmd, mapper, object, out)
|
return f.PrintObject(cmd, mapper, object, out)
|
||||||
}
|
}
|
||||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
||||||
|
@ -101,7 +101,7 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
usage := "Filename, directory, or URL to a file identifying the resource to update the labels"
|
usage := "Filename, directory, or URL to a file identifying the resource to update the labels"
|
||||||
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
||||||
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
||||||
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
cmdutil.AddRecordFlag(cmd)
|
||||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||||
|
|
||||||
@ -176,21 +176,9 @@ func labelFunc(obj runtime.Object, overwrite bool, resourceVersion string, label
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *LabelOptions) error {
|
func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *LabelOptions) error {
|
||||||
resources, labelArgs := []string{}, []string{}
|
resources, labelArgs, err := cmdutil.GetResourcesAndPairs(args, "label")
|
||||||
first := true
|
if err != nil {
|
||||||
for _, s := range args {
|
return err
|
||||||
isLabel := strings.Contains(s, "=") || strings.HasSuffix(s, "-")
|
|
||||||
switch {
|
|
||||||
case first && isLabel:
|
|
||||||
first = false
|
|
||||||
fallthrough
|
|
||||||
case !first && isLabel:
|
|
||||||
labelArgs = append(labelArgs, s)
|
|
||||||
case first && !isLabel:
|
|
||||||
resources = append(resources, s)
|
|
||||||
case !first && !isLabel:
|
|
||||||
return cmdutil.UsageError(cmd, "all resources must be specified before label changes: %s", s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(resources) < 1 && len(options.Filenames) == 0 {
|
if len(resources) < 1 && len(options.Filenames) == 0 {
|
||||||
return cmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
return cmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||||
@ -242,7 +230,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||||||
|
|
||||||
var outputObj runtime.Object
|
var outputObj runtime.Object
|
||||||
dataChangeMsg := "not labeled"
|
dataChangeMsg := "not labeled"
|
||||||
if cmdutil.GetFlagBool(cmd, "dry-run") {
|
if cmdutil.GetDryRunFlag(cmd) {
|
||||||
err = labelFunc(info.Object, overwrite, resourceVersion, lbls, remove)
|
err = labelFunc(info.Object, overwrite, resourceVersion, lbls, remove)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -98,8 +98,8 @@ func NewCmdRollingUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().String("deployment-label-key", "deployment", "The key to use to differentiate between two different controllers, default 'deployment'. Only relevant when --image is specified, ignored otherwise")
|
cmd.Flags().String("deployment-label-key", "deployment", "The key to use to differentiate between two different controllers, default 'deployment'. Only relevant when --image is specified, ignored otherwise")
|
||||||
cmd.Flags().String("container", "", "Container name which will have its image upgraded. Only relevant when --image is specified, ignored otherwise. Required when using --image on a multi-container pod")
|
cmd.Flags().String("container", "", "Container name which will have its image upgraded. Only relevant when --image is specified, ignored otherwise. Required when using --image on a multi-container pod")
|
||||||
cmd.Flags().String("image-pull-policy", "", "Explicit policy for when to pull container images. Required when --image is same as existing image, ignored otherwise.")
|
cmd.Flags().String("image-pull-policy", "", "Explicit policy for when to pull container images. Required when --image is same as existing image, ignored otherwise.")
|
||||||
cmd.Flags().Bool("dry-run", false, "If true, print out the changes that would be made, but don't actually make them.")
|
|
||||||
cmd.Flags().Bool("rollback", false, "If true, this is a request to abort an existing rollout that is partially rolled out. It effectively reverses current and next and runs a rollout")
|
cmd.Flags().Bool("rollback", false, "If true, this is a request to abort an existing rollout that is partially rolled out. It effectively reverses current and next and runs a rollout")
|
||||||
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddValidateFlags(cmd)
|
cmdutil.AddValidateFlags(cmd)
|
||||||
cmdutil.AddPrinterFlags(cmd)
|
cmdutil.AddPrinterFlags(cmd)
|
||||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||||
@ -157,7 +157,7 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
|
|||||||
period := cmdutil.GetFlagDuration(cmd, "update-period")
|
period := cmdutil.GetFlagDuration(cmd, "update-period")
|
||||||
interval := cmdutil.GetFlagDuration(cmd, "poll-interval")
|
interval := cmdutil.GetFlagDuration(cmd, "poll-interval")
|
||||||
timeout := cmdutil.GetFlagDuration(cmd, "timeout")
|
timeout := cmdutil.GetFlagDuration(cmd, "timeout")
|
||||||
dryrun := cmdutil.GetFlagBool(cmd, "dry-run")
|
dryrun := cmdutil.GetDryRunFlag(cmd)
|
||||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||||
container := cmdutil.GetFlagString(cmd, "container")
|
container := cmdutil.GetFlagString(cmd, "container")
|
||||||
|
|
||||||
|
@ -92,12 +92,12 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addRunFlags(cmd *cobra.Command) {
|
func addRunFlags(cmd *cobra.Command) {
|
||||||
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmd.Flags().String("generator", "", "The name of the API generator to use. Default is 'deployment/v1beta1' if --restart=Always, otherwise the default is 'job/v1'. This will happen only for cluster version at least 1.2, for olders we will fallback to 'run/v1' for --restart=Always, 'run-pod/v1' for others.")
|
cmd.Flags().String("generator", "", "The name of the API generator to use. Default is 'deployment/v1beta1' if --restart=Always, otherwise the default is 'job/v1'. This will happen only for cluster version at least 1.2, for olders we will fallback to 'run/v1' for --restart=Always, 'run-pod/v1' for others.")
|
||||||
cmd.Flags().String("image", "", "The image for the container to run.")
|
cmd.Flags().String("image", "", "The image for the container to run.")
|
||||||
cmd.MarkFlagRequired("image")
|
cmd.MarkFlagRequired("image")
|
||||||
cmd.Flags().IntP("replicas", "r", 1, "Number of replicas to create for this container. Default is 1.")
|
cmd.Flags().IntP("replicas", "r", 1, "Number of replicas to create for this container. Default is 1.")
|
||||||
cmd.Flags().Bool("rm", false, "If true, delete resources created in this command for attached containers.")
|
cmd.Flags().Bool("rm", false, "If true, delete resources created in this command for attached containers.")
|
||||||
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
|
|
||||||
cmd.Flags().String("overrides", "", "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.")
|
cmd.Flags().String("overrides", "", "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.")
|
||||||
cmd.Flags().StringSlice("env", []string{}, "Environment variables to set in the container")
|
cmd.Flags().StringSlice("env", []string{}, "Environment variables to set in the container")
|
||||||
cmd.Flags().Int("port", -1, "The port that this container exposes. If --expose is true, this is also the port used by the service that is created.")
|
cmd.Flags().Int("port", -1, "The port that this container exposes. If --expose is true, this is also the port used by the service that is created.")
|
||||||
@ -474,8 +474,7 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
|
|||||||
return nil, "", nil, nil, err
|
return nil, "", nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: extract this flag to a central location, when such a location exists.
|
if !cmdutil.GetDryRunFlag(cmd) {
|
||||||
if !cmdutil.GetFlagBool(cmd, "dry-run") {
|
|
||||||
resourceMapper := &resource.Mapper{
|
resourceMapper := &resource.Mapper{
|
||||||
ObjectTyper: typer,
|
ObjectTyper: typer,
|
||||||
RESTMapper: mapper,
|
RESTMapper: mapper,
|
||||||
|
151
pkg/kubectl/cmd/set/helper.go
Normal file
151
pkg/kubectl/cmd/set/helper.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
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 set
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// selectContainers allows one or more containers to be matched against a string or wildcard
|
||||||
|
func selectContainers(containers []api.Container, spec string) ([]*api.Container, []*api.Container) {
|
||||||
|
out := []*api.Container{}
|
||||||
|
skipped := []*api.Container{}
|
||||||
|
for i, c := range containers {
|
||||||
|
if selectString(c.Name, spec) {
|
||||||
|
out = append(out, &containers[i])
|
||||||
|
} else {
|
||||||
|
skipped = append(skipped, &containers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, skipped
|
||||||
|
}
|
||||||
|
|
||||||
|
// handlePodUpdateError prints a more useful error to the end user when mutating a pod.
|
||||||
|
func handlePodUpdateError(out io.Writer, err error, resource string) {
|
||||||
|
if statusError, ok := err.(*errors.StatusError); ok && errors.IsInvalid(err) {
|
||||||
|
errorDetails := statusError.Status().Details
|
||||||
|
if errorDetails.Kind == "Pod" {
|
||||||
|
all, match := true, false
|
||||||
|
for _, cause := range errorDetails.Causes {
|
||||||
|
if cause.Field == "spec" && strings.Contains(cause.Message, "may not update fields other than") {
|
||||||
|
fmt.Fprintf(out, "error: may not update %s in pod %q directly\n", resource, errorDetails.Name)
|
||||||
|
match = true
|
||||||
|
} else {
|
||||||
|
all = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if all && match {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(out, "error: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectString returns true if the provided string matches spec, where spec is a string with
|
||||||
|
// a non-greedy '*' wildcard operator.
|
||||||
|
// TODO: turn into a regex and handle greedy matches and backtracking.
|
||||||
|
func selectString(s, spec string) bool {
|
||||||
|
if spec == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !strings.Contains(spec, "*") {
|
||||||
|
return s == spec
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := 0
|
||||||
|
match := true
|
||||||
|
parts := strings.Split(spec, "*")
|
||||||
|
for i, part := range parts {
|
||||||
|
if len(part) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
next := strings.Index(s[pos:], part)
|
||||||
|
switch {
|
||||||
|
// next part not in string
|
||||||
|
case next < pos:
|
||||||
|
fallthrough
|
||||||
|
// first part does not match start of string
|
||||||
|
case i == 0 && pos != 0:
|
||||||
|
fallthrough
|
||||||
|
// last part does not exactly match remaining part of string
|
||||||
|
case i == (len(parts)-1) && len(s) != (len(part)+next):
|
||||||
|
match = false
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
pos = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch represents the result of a mutation to an object.
|
||||||
|
type Patch struct {
|
||||||
|
Info *resource.Info
|
||||||
|
Err error
|
||||||
|
|
||||||
|
Before []byte
|
||||||
|
After []byte
|
||||||
|
Patch []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalculatePatches calls the mutation function on each provided info object, and generates a strategic merge patch for
|
||||||
|
// the changes in the object. Encoder must be able to encode the info into the appropriate destination type. If mutateFn
|
||||||
|
// returns false, the object is not included in the final list of patches.
|
||||||
|
func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn func(*resource.Info) (bool, error)) []*Patch {
|
||||||
|
var patches []*Patch
|
||||||
|
for _, info := range infos {
|
||||||
|
patch := &Patch{Info: info}
|
||||||
|
patch.Before, patch.Err = runtime.Encode(encoder, info.Object)
|
||||||
|
|
||||||
|
ok, err := mutateFn(info)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
patch.Err = err
|
||||||
|
}
|
||||||
|
patches = append(patches, patch)
|
||||||
|
if patch.Err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
patch.After, patch.Err = runtime.Encode(encoder, info.Object)
|
||||||
|
if patch.Err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: should be via New
|
||||||
|
versioned, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||||
|
if err != nil {
|
||||||
|
patch.Err = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, versioned)
|
||||||
|
}
|
||||||
|
return patches
|
||||||
|
}
|
@ -42,7 +42,8 @@ func NewCmdSet(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add subcommands
|
// add subcommands
|
||||||
|
cmd.AddCommand(NewCmdImage(f, out))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
239
pkg/kubectl/cmd/set/set_image.go
Normal file
239
pkg/kubectl/cmd/set/set_image.go
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
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 set
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImageOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
|
||||||
|
// referencing the cmd.Flags()
|
||||||
|
type ImageOptions struct {
|
||||||
|
Mapper meta.RESTMapper
|
||||||
|
Typer runtime.ObjectTyper
|
||||||
|
Infos []*resource.Info
|
||||||
|
Encoder runtime.Encoder
|
||||||
|
Selector string
|
||||||
|
Out io.Writer
|
||||||
|
Err io.Writer
|
||||||
|
Filenames []string
|
||||||
|
Recursive bool
|
||||||
|
ShortOutput bool
|
||||||
|
All bool
|
||||||
|
Record bool
|
||||||
|
ChangeCause string
|
||||||
|
Local bool
|
||||||
|
Cmd *cobra.Command
|
||||||
|
|
||||||
|
PrintObject func(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error
|
||||||
|
UpdatePodSpecForObject func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error)
|
||||||
|
Resources []string
|
||||||
|
ContainerImages map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
image_resources = `
|
||||||
|
pod (po), replicationcontroller (rc), deployment, daemonset (ds), job, replicaset (rs)`
|
||||||
|
|
||||||
|
image_long = `Update existing container image(s) of resources.
|
||||||
|
|
||||||
|
Possible resources include (case insensitive):` + image_resources
|
||||||
|
|
||||||
|
image_example = `# Set a deployment's nginx container image to 'nginx:1.9.1', and its busybox container image to 'busybox'.
|
||||||
|
kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
|
||||||
|
|
||||||
|
# Update all deployments' and rc's nginx container's image to 'nginx:1.9.1'
|
||||||
|
kubectl set image deployments,rc nginx=nginx:1.9.1 --all
|
||||||
|
|
||||||
|
# Update image of all containers of daemonset abc to 'nginx:1.9.1'
|
||||||
|
kubectl set image daemonset abc *=nginx:1.9.1
|
||||||
|
|
||||||
|
# Print result (in yaml format) of updating nginx container image from local file, without hitting the server
|
||||||
|
kubectl set image -f path/to/file.yaml nginx=nginx:1.9.1 --local -o yaml`
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCmdImage(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
|
options := &ImageOptions{
|
||||||
|
Out: out,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N",
|
||||||
|
Short: "Update image of a pod template",
|
||||||
|
Long: image_long,
|
||||||
|
Example: image_example,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||||
|
cmdutil.CheckErr(options.Validate())
|
||||||
|
cmdutil.CheckErr(options.Run())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdutil.AddPrinterFlags(cmd)
|
||||||
|
usage := "Filename, directory, or URL to a file identifying the resource to get from a server."
|
||||||
|
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
|
||||||
|
cmd.Flags().BoolVar(&options.All, "all", false, "select all resources in the namespace of the specified resource types")
|
||||||
|
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on")
|
||||||
|
cmd.Flags().BoolVar(&options.Local, "local", false, "If true, set image will NOT contact api-server but run locally.")
|
||||||
|
cmdutil.AddRecordFlag(cmd)
|
||||||
|
cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ImageOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
|
o.Mapper, o.Typer = f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
|
||||||
|
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||||
|
o.Encoder = f.JSONEncoder()
|
||||||
|
o.ShortOutput = cmdutil.GetFlagString(cmd, "output") == "name"
|
||||||
|
o.Record = cmdutil.GetRecordFlag(cmd)
|
||||||
|
o.ChangeCause = f.Command()
|
||||||
|
o.PrintObject = f.PrintObject
|
||||||
|
o.Cmd = cmd
|
||||||
|
|
||||||
|
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Resources, o.ContainerImages, err = getResourcesAndImages(args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||||
|
ContinueOnError().
|
||||||
|
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||||
|
FilenameParam(enforceNamespace, o.Recursive, o.Filenames...).
|
||||||
|
Flatten()
|
||||||
|
if !o.Local {
|
||||||
|
builder = builder.
|
||||||
|
SelectorParam(o.Selector).
|
||||||
|
ResourceTypeOrNameArgs(o.All, o.Resources...).
|
||||||
|
Latest()
|
||||||
|
}
|
||||||
|
o.Infos, err = builder.Do().Infos()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ImageOptions) Validate() error {
|
||||||
|
if len(o.Resources) < 1 && len(o.Filenames) == 0 {
|
||||||
|
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||||
|
}
|
||||||
|
if len(o.ContainerImages) < 1 {
|
||||||
|
return fmt.Errorf("at least one image update is required")
|
||||||
|
} else if len(o.ContainerImages) > 1 && hasWildcardKey(o.ContainerImages) {
|
||||||
|
return fmt.Errorf("all containers are already specified by *, but saw more than one container_name=container_image pairs")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ImageOptions) Run() error {
|
||||||
|
allErrs := []error{}
|
||||||
|
|
||||||
|
patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) (bool, error) {
|
||||||
|
transformed := false
|
||||||
|
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
|
||||||
|
for name, image := range o.ContainerImages {
|
||||||
|
containerFound := false
|
||||||
|
// Find the container to update, and update its image
|
||||||
|
for i, c := range spec.Containers {
|
||||||
|
if c.Name == name || name == "*" {
|
||||||
|
spec.Containers[i].Image = image
|
||||||
|
containerFound = true
|
||||||
|
// Perform updates
|
||||||
|
transformed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add a new container if not found
|
||||||
|
if !containerFound {
|
||||||
|
allErrs = append(allErrs, fmt.Errorf("error: unable to find container named %q", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return transformed, err
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, patch := range patches {
|
||||||
|
info := patch.Info
|
||||||
|
if patch.Err != nil {
|
||||||
|
allErrs = append(allErrs, fmt.Errorf("error: %s/%s %v\n", info.Mapping.Resource, info.Name, patch.Err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// no changes
|
||||||
|
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.Local {
|
||||||
|
fmt.Fprintln(o.Out, "running in local mode...")
|
||||||
|
return o.PrintObject(o.Cmd, o.Mapper, info.Object, o.Out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch the change
|
||||||
|
obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch.Patch)
|
||||||
|
if err != nil {
|
||||||
|
allErrs = append(allErrs, fmt.Errorf("failed to patch image update to pod template: %v\n", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info.Refresh(obj, true)
|
||||||
|
|
||||||
|
// record this change (for rollout history)
|
||||||
|
if o.Record || cmdutil.ContainsChangeCause(info) {
|
||||||
|
if err := cmdutil.RecordChangeCause(obj, o.ChangeCause); err == nil {
|
||||||
|
if obj, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, obj); err != nil {
|
||||||
|
allErrs = append(allErrs, fmt.Errorf("changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.Refresh(obj, true)
|
||||||
|
cmdutil.PrintSuccess(o.Mapper, o.ShortOutput, o.Out, info.Mapping.Resource, info.Name, "image updated")
|
||||||
|
}
|
||||||
|
return utilerrors.NewAggregate(allErrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getResourcesAndImages retrieves resources and container name:images pair from given args
|
||||||
|
func getResourcesAndImages(args []string) (resources []string, containerImages map[string]string, err error) {
|
||||||
|
pairType := "image"
|
||||||
|
resources, imageArgs, err := cmdutil.GetResourcesAndPairs(args, pairType)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
containerImages, _, err = cmdutil.ParsePairs(imageArgs, pairType, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasWildcardKey(containerImages map[string]string) bool {
|
||||||
|
_, ok := containerImages["*"]
|
||||||
|
return ok
|
||||||
|
}
|
@ -139,6 +139,9 @@ type Factory struct {
|
|||||||
CanBeAutoscaled func(kind unversioned.GroupKind) error
|
CanBeAutoscaled func(kind unversioned.GroupKind) error
|
||||||
// AttachablePodForObject returns the pod to which to attach given an object.
|
// AttachablePodForObject returns the pod to which to attach given an object.
|
||||||
AttachablePodForObject func(object runtime.Object) (*api.Pod, error)
|
AttachablePodForObject func(object runtime.Object) (*api.Pod, error)
|
||||||
|
// UpdatePodSpecForObject will call the provided function on the pod spec this object supports,
|
||||||
|
// return false if no pod spec is supported, or return an error.
|
||||||
|
UpdatePodSpecForObject func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error)
|
||||||
// EditorEnvs returns a group of environment variables that the edit command
|
// EditorEnvs returns a group of environment variables that the edit command
|
||||||
// can range over in order to determine if the user has specified an editor
|
// can range over in order to determine if the user has specified an editor
|
||||||
// of their choice.
|
// of their choice.
|
||||||
@ -708,6 +711,31 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk)
|
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// UpdatePodSpecForObject update the pod specification for the provided object
|
||||||
|
UpdatePodSpecForObject: func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) {
|
||||||
|
// TODO: replace with a swagger schema based approach (identify pod template via schema introspection)
|
||||||
|
switch t := obj.(type) {
|
||||||
|
case *api.Pod:
|
||||||
|
return true, fn(&t.Spec)
|
||||||
|
case *api.ReplicationController:
|
||||||
|
if t.Spec.Template == nil {
|
||||||
|
t.Spec.Template = &api.PodTemplateSpec{}
|
||||||
|
}
|
||||||
|
return true, fn(&t.Spec.Template.Spec)
|
||||||
|
case *extensions.Deployment:
|
||||||
|
return true, fn(&t.Spec.Template.Spec)
|
||||||
|
case *extensions.DaemonSet:
|
||||||
|
return true, fn(&t.Spec.Template.Spec)
|
||||||
|
case *extensions.ReplicaSet:
|
||||||
|
return true, fn(&t.Spec.Template.Spec)
|
||||||
|
case *apps.PetSet:
|
||||||
|
return true, fn(&t.Spec.Template.Spec)
|
||||||
|
case *batch.Job:
|
||||||
|
return true, fn(&t.Spec.Template.Spec)
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf("the object is not a pod or does not have a pod template")
|
||||||
|
}
|
||||||
|
},
|
||||||
EditorEnvs: func() []string {
|
EditorEnvs: func() []string {
|
||||||
return []string{"KUBE_EDITOR", "EDITOR"}
|
return []string{"KUBE_EDITOR", "EDITOR"}
|
||||||
},
|
},
|
||||||
|
@ -336,6 +336,11 @@ func AddRecursiveFlag(cmd *cobra.Command, value *bool) {
|
|||||||
cmd.Flags().BoolVarP(value, "recursive", "R", *value, "If true, process directory recursively.")
|
cmd.Flags().BoolVarP(value, "recursive", "R", *value, "If true, process directory recursively.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDryRunFlag adds dry-run flag to a command. Usually used by mutations.
|
||||||
|
func AddDryRunFlag(cmd *cobra.Command) {
|
||||||
|
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
|
||||||
|
}
|
||||||
|
|
||||||
func AddApplyAnnotationFlags(cmd *cobra.Command) {
|
func AddApplyAnnotationFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().Bool(ApplyAnnotationsFlag, false, "If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.")
|
cmd.Flags().Bool(ApplyAnnotationsFlag, false, "If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.")
|
||||||
}
|
}
|
||||||
@ -344,7 +349,7 @@ func AddApplyAnnotationFlags(cmd *cobra.Command) {
|
|||||||
// TODO: need to take a pass at other generator commands to use this set of flags
|
// TODO: need to take a pass at other generator commands to use this set of flags
|
||||||
func AddGeneratorFlags(cmd *cobra.Command, defaultGenerator string) {
|
func AddGeneratorFlags(cmd *cobra.Command, defaultGenerator string) {
|
||||||
cmd.Flags().String("generator", defaultGenerator, "The name of the API generator to use.")
|
cmd.Flags().String("generator", defaultGenerator, "The name of the API generator to use.")
|
||||||
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
|
AddDryRunFlag(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadConfigDataFromReader(reader io.Reader, source string) ([]byte, error) {
|
func ReadConfigDataFromReader(reader io.Reader, source string) ([]byte, error) {
|
||||||
@ -433,6 +438,10 @@ func GetRecordFlag(cmd *cobra.Command) bool {
|
|||||||
return GetFlagBool(cmd, "record")
|
return GetFlagBool(cmd, "record")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDryRunFlag(cmd *cobra.Command) bool {
|
||||||
|
return GetFlagBool(cmd, "dry-run")
|
||||||
|
}
|
||||||
|
|
||||||
// RecordChangeCause annotate change-cause to input runtime object.
|
// RecordChangeCause annotate change-cause to input runtime object.
|
||||||
func RecordChangeCause(obj runtime.Object, changeCause string) error {
|
func RecordChangeCause(obj runtime.Object, changeCause string) error {
|
||||||
accessor, err := meta.Accessor(obj)
|
accessor, err := meta.Accessor(obj)
|
||||||
@ -528,3 +537,60 @@ func GetIncludeThirdPartyAPIs(cmd *cobra.Command) bool {
|
|||||||
func AddInclude3rdPartyFlags(cmd *cobra.Command) {
|
func AddInclude3rdPartyFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().Bool("include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
|
cmd.Flags().Bool("include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResourcesAndPairs retrieves resources and "KEY=VALUE or KEY-" pair args from given args
|
||||||
|
func GetResourcesAndPairs(args []string, pairType string) (resources []string, pairArgs []string, err error) {
|
||||||
|
foundPair := false
|
||||||
|
for _, s := range args {
|
||||||
|
nonResource := strings.Contains(s, "=") || strings.HasSuffix(s, "-")
|
||||||
|
switch {
|
||||||
|
case !foundPair && nonResource:
|
||||||
|
foundPair = true
|
||||||
|
fallthrough
|
||||||
|
case foundPair && nonResource:
|
||||||
|
pairArgs = append(pairArgs, s)
|
||||||
|
case !foundPair && !nonResource:
|
||||||
|
resources = append(resources, s)
|
||||||
|
case foundPair && !nonResource:
|
||||||
|
err = fmt.Errorf("all resources must be specified before %s changes: %s", pairType, s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePairs retrieves new and remove pairs (if supportRemove is true) from "KEY=VALUE or KEY-" pair args
|
||||||
|
func ParsePairs(pairArgs []string, pairType string, supportRemove bool) (newPairs map[string]string, removePairs []string, err error) {
|
||||||
|
newPairs = map[string]string{}
|
||||||
|
if supportRemove {
|
||||||
|
removePairs = []string{}
|
||||||
|
}
|
||||||
|
var invalidBuf bytes.Buffer
|
||||||
|
|
||||||
|
for _, pairArg := range pairArgs {
|
||||||
|
if strings.Index(pairArg, "=") != -1 {
|
||||||
|
parts := strings.SplitN(pairArg, "=", 2)
|
||||||
|
if len(parts) != 2 || len(parts[1]) == 0 {
|
||||||
|
if invalidBuf.Len() > 0 {
|
||||||
|
invalidBuf.WriteString(", ")
|
||||||
|
}
|
||||||
|
invalidBuf.WriteString(fmt.Sprintf(pairArg))
|
||||||
|
} else {
|
||||||
|
newPairs[parts[0]] = parts[1]
|
||||||
|
}
|
||||||
|
} else if supportRemove && strings.HasSuffix(pairArg, "-") {
|
||||||
|
removePairs = append(removePairs, pairArg[:len(pairArg)-1])
|
||||||
|
} else {
|
||||||
|
if invalidBuf.Len() > 0 {
|
||||||
|
invalidBuf.WriteString(", ")
|
||||||
|
}
|
||||||
|
invalidBuf.WriteString(fmt.Sprintf(pairArg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if invalidBuf.Len() > 0 {
|
||||||
|
err = fmt.Errorf("invalid %s format: %s", pairType, invalidBuf.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user