From 5088d0e1474c25facdb1126ed0f885b4c6425a8b Mon Sep 17 00:00:00 2001 From: Janet Kuo Date: Fri, 22 Jan 2016 10:33:23 -0800 Subject: [PATCH] Record kubectl commands --- contrib/completions/bash/kubectl | 11 ++++ docs/man/man1/kubectl-annotate.1 | 4 ++ docs/man/man1/kubectl-apply.1 | 4 ++ docs/man/man1/kubectl-autoscale.1 | 4 ++ docs/man/man1/kubectl-create.1 | 4 ++ docs/man/man1/kubectl-edit.1 | 4 ++ docs/man/man1/kubectl-expose.1 | 4 ++ docs/man/man1/kubectl-label.1 | 4 ++ docs/man/man1/kubectl-patch.1 | 4 ++ docs/man/man1/kubectl-replace.1 | 4 ++ docs/man/man1/kubectl-run.1 | 4 ++ docs/man/man1/kubectl-scale.1 | 4 ++ docs/user-guide/kubectl/kubectl_annotate.md | 3 +- docs/user-guide/kubectl/kubectl_apply.md | 3 +- docs/user-guide/kubectl/kubectl_autoscale.md | 3 +- docs/user-guide/kubectl/kubectl_create.md | 3 +- docs/user-guide/kubectl/kubectl_edit.md | 3 +- docs/user-guide/kubectl/kubectl_expose.md | 3 +- docs/user-guide/kubectl/kubectl_label.md | 3 +- docs/user-guide/kubectl/kubectl_patch.md | 3 +- docs/user-guide/kubectl/kubectl_replace.md | 3 +- docs/user-guide/kubectl/kubectl_run.md | 3 +- docs/user-guide/kubectl/kubectl_scale.md | 3 +- .../deployment/deployment_controller.go | 7 +++ pkg/kubectl/cmd/annotate.go | 15 +++++ pkg/kubectl/cmd/apply.go | 19 +++++++ pkg/kubectl/cmd/autoscale.go | 7 +++ pkg/kubectl/cmd/create.go | 7 +++ pkg/kubectl/cmd/edit.go | 7 +++ pkg/kubectl/cmd/expose.go | 7 +++ pkg/kubectl/cmd/label.go | 6 ++ pkg/kubectl/cmd/patch.go | 11 ++++ pkg/kubectl/cmd/replace.go | 13 +++++ pkg/kubectl/cmd/run.go | 10 ++++ pkg/kubectl/cmd/run_test.go | 1 + pkg/kubectl/cmd/scale.go | 20 +++++++ pkg/kubectl/cmd/util/factory.go | 14 +++++ pkg/kubectl/cmd/util/helpers.go | 56 +++++++++++++++++++ 38 files changed, 277 insertions(+), 11 deletions(-) diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 03af9e59d8..2afcb8ea9f 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -616,6 +616,7 @@ _kubectl_create() flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--output=") two_word_flags+=("-o") + flags+=("--record") flags+=("--save-config") flags+=("--schema-cache-dir=") flags+=("--validate") @@ -671,6 +672,7 @@ _kubectl_replace() flags+=("--grace-period=") flags+=("--output=") two_word_flags+=("-o") + flags+=("--record") flags+=("--save-config") flags+=("--schema-cache-dir=") flags+=("--timeout=") @@ -726,6 +728,7 @@ _kubectl_patch() two_word_flags+=("-o") flags+=("--patch=") two_word_flags+=("-p") + flags+=("--record") flags+=("--alsologtostderr") flags+=("--api-version=") flags+=("--certificate-authority=") @@ -852,6 +855,7 @@ _kubectl_edit() flags+=("--output=") two_word_flags+=("-o") flags+=("--output-version=") + flags+=("--record") flags+=("--save-config") flags+=("--windows-line-endings") flags+=("--alsologtostderr") @@ -901,6 +905,7 @@ _kubectl_apply() flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--output=") two_word_flags+=("-o") + flags+=("--record") flags+=("--schema-cache-dir=") flags+=("--validate") flags+=("--alsologtostderr") @@ -1110,6 +1115,7 @@ _kubectl_scale() flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--output=") two_word_flags+=("-o") + flags+=("--record") flags+=("--replicas=") flags+=("--resource-version=") flags+=("--timeout=") @@ -1477,6 +1483,7 @@ _kubectl_run() flags+=("--output-version=") flags+=("--overrides=") flags+=("--port=") + flags+=("--record") flags+=("--replicas=") two_word_flags+=("-r") flags+=("--requests=") @@ -1555,6 +1562,7 @@ _kubectl_expose() flags+=("--overrides=") flags+=("--port=") flags+=("--protocol=") + flags+=("--record") flags+=("--save-config") flags+=("--selector=") flags+=("--session-affinity=") @@ -1620,6 +1628,7 @@ _kubectl_autoscale() flags+=("--output=") two_word_flags+=("-o") flags+=("--output-version=") + flags+=("--record") flags+=("--save-config") flags+=("--show-all") flags+=("-a") @@ -1857,6 +1866,7 @@ _kubectl_label() two_word_flags+=("-o") flags+=("--output-version=") flags+=("--overwrite") + flags+=("--record") flags+=("--resource-version=") flags+=("--selector=") two_word_flags+=("-l") @@ -1938,6 +1948,7 @@ _kubectl_annotate() two_word_flags+=("-o") flags+=("--output-version=") flags+=("--overwrite") + flags+=("--record") flags+=("--resource-version=") flags+=("--selector=") two_word_flags+=("-l") diff --git a/docs/man/man1/kubectl-annotate.1 b/docs/man/man1/kubectl-annotate.1 index 84de22540f..3ff4336f22 100644 --- a/docs/man/man1/kubectl-annotate.1 +++ b/docs/man/man1/kubectl-annotate.1 @@ -55,6 +55,10 @@ horizontalpodautoscalers (hpa), resourcequotas (quota) or secrets. \fB\-\-overwrite\fP=false If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations. +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-resource\-version\fP="" If non\-empty, the annotation update will only succeed if this is the current resource\-version for the object. Only valid when specifying a single resource. diff --git a/docs/man/man1/kubectl-apply.1 b/docs/man/man1/kubectl-apply.1 index ad0418b322..a5f3d080e0 100644 --- a/docs/man/man1/kubectl-apply.1 +++ b/docs/man/man1/kubectl-apply.1 @@ -29,6 +29,10 @@ JSON and YAML formats are accepted. \fB\-o\fP, \fB\-\-output\fP="" Output mode. Use "\-o name" for shorter output (resource/name). +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-schema\-cache\-dir\fP="\~/.kube/schema" If non\-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema' diff --git a/docs/man/man1/kubectl-autoscale.1 b/docs/man/man1/kubectl-autoscale.1 index 348f55e05e..867e4471b4 100644 --- a/docs/man/man1/kubectl-autoscale.1 +++ b/docs/man/man1/kubectl-autoscale.1 @@ -63,6 +63,10 @@ An autoscaler can automatically increase or decrease number of pods deployed wit \fB\-\-output\-version\fP="" Output the formatted object with the given version (default api\-version). +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-save\-config\fP=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. diff --git a/docs/man/man1/kubectl-create.1 b/docs/man/man1/kubectl-create.1 index e10b782855..958b3ec2c7 100644 --- a/docs/man/man1/kubectl-create.1 +++ b/docs/man/man1/kubectl-create.1 @@ -28,6 +28,10 @@ JSON and YAML formats are accepted. \fB\-o\fP, \fB\-\-output\fP="" Output mode. Use "\-o name" for shorter output (resource/name). +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-save\-config\fP=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. diff --git a/docs/man/man1/kubectl-edit.1 b/docs/man/man1/kubectl-edit.1 index 0e833a7d1f..5ac2eee6ab 100644 --- a/docs/man/man1/kubectl-edit.1 +++ b/docs/man/man1/kubectl-edit.1 @@ -50,6 +50,10 @@ saved copy to include the latest resource version. \fB\-\-output\-version\fP="" Output the formatted object with the given version (default api\-version). +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-save\-config\fP=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. diff --git a/docs/man/man1/kubectl-expose.1 b/docs/man/man1/kubectl-expose.1 index 0be697f7a2..6865f091b7 100644 --- a/docs/man/man1/kubectl-expose.1 +++ b/docs/man/man1/kubectl-expose.1 @@ -85,6 +85,10 @@ the new service will re\-use the labels from the resource it exposes. \fB\-\-protocol\fP="TCP" The network protocol for the service to be created. Default is 'tcp'. +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-save\-config\fP=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. diff --git a/docs/man/man1/kubectl-label.1 b/docs/man/man1/kubectl-label.1 index 755962a8bc..ea14efdac4 100644 --- a/docs/man/man1/kubectl-label.1 +++ b/docs/man/man1/kubectl-label.1 @@ -52,6 +52,10 @@ If \-\-resource\-version is specified, then updates will use this resource versi \fB\-\-overwrite\fP=false If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels. +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-resource\-version\fP="" If non\-empty, the labels update will only succeed if this is the current resource\-version for the object. Only valid when specifying a single resource. diff --git a/docs/man/man1/kubectl-patch.1 b/docs/man/man1/kubectl-patch.1 index 454684f825..ca1f108992 100644 --- a/docs/man/man1/kubectl-patch.1 +++ b/docs/man/man1/kubectl-patch.1 @@ -36,6 +36,10 @@ Please refer to the models in \fB\-p\fP, \fB\-\-patch\fP="" The patch to be applied to the resource JSON file. +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .SH OPTIONS INHERITED FROM PARENT COMMANDS .PP diff --git a/docs/man/man1/kubectl-replace.1 b/docs/man/man1/kubectl-replace.1 index 3418877c5e..33eb80b768 100644 --- a/docs/man/man1/kubectl-replace.1 +++ b/docs/man/man1/kubectl-replace.1 @@ -46,6 +46,10 @@ Please refer to the models in \fB\-o\fP, \fB\-\-output\fP="" Output mode. Use "\-o name" for shorter output (resource/name). +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-save\-config\fP=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. diff --git a/docs/man/man1/kubectl-run.1 b/docs/man/man1/kubectl-run.1 index bea0069e3b..9131f717d0 100644 --- a/docs/man/man1/kubectl-run.1 +++ b/docs/man/man1/kubectl-run.1 @@ -84,6 +84,10 @@ Creates a replication controller or job to manage the created container(s). \fB\-\-port\fP=\-1 The port that this container exposes. If \-\-expose is true, this is also the port used by the service that is created. +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-r\fP, \fB\-\-replicas\fP=1 Number of replicas to create for this container. Default is 1. diff --git a/docs/man/man1/kubectl-scale.1 b/docs/man/man1/kubectl-scale.1 index cea0bafa12..92b4f2daaf 100644 --- a/docs/man/man1/kubectl-scale.1 +++ b/docs/man/man1/kubectl-scale.1 @@ -35,6 +35,10 @@ scale is sent to the server. \fB\-o\fP, \fB\-\-output\fP="" Output mode. Use "\-o name" for shorter output (resource/name). +.PP +\fB\-\-record\fP=false + Record current kubectl command in the resource annotation. + .PP \fB\-\-replicas\fP=\-1 The new desired number of replicas. Required. diff --git a/docs/user-guide/kubectl/kubectl_annotate.md b/docs/user-guide/kubectl/kubectl_annotate.md index 6cf45f22c9..5812ff4b6b 100644 --- a/docs/user-guide/kubectl/kubectl_annotate.md +++ b/docs/user-guide/kubectl/kubectl_annotate.md @@ -88,6 +88,7 @@ $ kubectl annotate pods foo description- -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 version (default api-version). --overwrite[=false]: If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations. + --record[=false]: Record current kubectl command in the resource annotation. --resource-version="": If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource. -l, --selector="": Selector (label query) to filter on -a, --show-all[=false]: When printing, show all resources (default hide terminated pods.) @@ -127,7 +128,7 @@ $ kubectl annotate pods foo description- * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_annotate.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_apply.md b/docs/user-guide/kubectl/kubectl_apply.md index f447378517..0d2fca94f5 100644 --- a/docs/user-guide/kubectl/kubectl_apply.md +++ b/docs/user-guide/kubectl/kubectl_apply.md @@ -63,6 +63,7 @@ $ cat pod.json | kubectl apply -f - ``` -f, --filename=[]: Filename, directory, or URL to file that contains the configuration to apply -o, --output="": Output mode. Use "-o name" for shorter output (resource/name). + --record[=false]: Record current kubectl command in the resource annotation. --schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema' --validate[=true]: If true, use a schema to validate the input before sending it ``` @@ -99,7 +100,7 @@ $ cat pod.json | kubectl apply -f - * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_apply.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_autoscale.md b/docs/user-guide/kubectl/kubectl_autoscale.md index f2477073a6..61c0ff530e 100644 --- a/docs/user-guide/kubectl/kubectl_autoscale.md +++ b/docs/user-guide/kubectl/kubectl_autoscale.md @@ -71,6 +71,7 @@ $ kubectl autoscale rc foo --max=5 --cpu-percent=80 --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 version (default api-version). + --record[=false]: Record current kubectl command in the resource annotation. --save-config[=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. -a, --show-all[=false]: When printing, show all resources (default hide terminated pods.) --sort-by="": If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. 'ObjectMeta.Name'). The field in the API resource specified by this JSONPath expression must be an integer or a string. @@ -109,7 +110,7 @@ $ kubectl autoscale rc foo --max=5 --cpu-percent=80 * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_autoscale.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_create.md b/docs/user-guide/kubectl/kubectl_create.md index b3c25d9417..4ac999e08e 100644 --- a/docs/user-guide/kubectl/kubectl_create.md +++ b/docs/user-guide/kubectl/kubectl_create.md @@ -62,6 +62,7 @@ $ cat pod.json | kubectl create -f - ``` -f, --filename=[]: Filename, directory, or URL to file to use to create the resource -o, --output="": Output mode. Use "-o name" for shorter output (resource/name). + --record[=false]: Record current kubectl command in the resource annotation. --save-config[=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. --schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema' --validate[=true]: If true, use a schema to validate the input before sending it @@ -101,7 +102,7 @@ $ cat pod.json | kubectl create -f - * [kubectl create namespace](kubectl_create_namespace.md) - Create a namespace with the specified name. * [kubectl create secret](kubectl_create_secret.md) - Create a secret using specified subcommand. -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_create.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_edit.md b/docs/user-guide/kubectl/kubectl_edit.md index bd719a673f..ee8ec24b66 100644 --- a/docs/user-guide/kubectl/kubectl_edit.md +++ b/docs/user-guide/kubectl/kubectl_edit.md @@ -82,6 +82,7 @@ kubectl edit (RESOURCE/NAME | -f FILENAME) -f, --filename=[]: Filename, directory, or URL to file to use to edit the resource -o, --output="yaml": Output format. One of: yaml|json. --output-version="": Output the formatted object with the given version (default api-version). + --record[=false]: Record current kubectl command in the resource annotation. --save-config[=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. --windows-line-endings[=false]: Use Windows line-endings (default Unix line-endings) ``` @@ -118,7 +119,7 @@ kubectl edit (RESOURCE/NAME | -f FILENAME) * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_edit.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_expose.md b/docs/user-guide/kubectl/kubectl_expose.md index 25c62661c9..79e524157d 100644 --- a/docs/user-guide/kubectl/kubectl_expose.md +++ b/docs/user-guide/kubectl/kubectl_expose.md @@ -86,6 +86,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream --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. --port="": The port that the service should serve on. Copied from the resource being exposed, if unspecified --protocol="TCP": The network protocol for the service to be created. Default is 'tcp'. + --record[=false]: Record current kubectl command in the resource annotation. --save-config[=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. --selector="": A label selector to use for this service. If empty (the default) infer the selector from the replication controller. --session-affinity="": If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP' @@ -128,7 +129,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 10-Jan-2016 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_expose.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_label.md b/docs/user-guide/kubectl/kubectl_label.md index 09339404f3..9455fff8e2 100644 --- a/docs/user-guide/kubectl/kubectl_label.md +++ b/docs/user-guide/kubectl/kubectl_label.md @@ -82,6 +82,7 @@ $ kubectl label pods foo bar- -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 version (default api-version). --overwrite[=false]: If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels. + --record[=false]: Record current kubectl command in the resource annotation. --resource-version="": If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource. -l, --selector="": Selector (label query) to filter on -a, --show-all[=false]: When printing, show all resources (default hide terminated pods.) @@ -121,7 +122,7 @@ $ kubectl label pods foo bar- * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_label.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_patch.md b/docs/user-guide/kubectl/kubectl_patch.md index 91fb4c841a..6d67664c4a 100644 --- a/docs/user-guide/kubectl/kubectl_patch.md +++ b/docs/user-guide/kubectl/kubectl_patch.md @@ -69,6 +69,7 @@ kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve -f, --filename=[]: Filename, directory, or URL to a file identifying the resource to update -o, --output="": Output mode. Use "-o name" for shorter output (resource/name). -p, --patch="": The patch to be applied to the resource JSON file. + --record[=false]: Record current kubectl command in the resource annotation. ``` ### Options inherited from parent commands @@ -103,7 +104,7 @@ kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_patch.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_replace.md b/docs/user-guide/kubectl/kubectl_replace.md index f1bedbf948..100f3dff75 100644 --- a/docs/user-guide/kubectl/kubectl_replace.md +++ b/docs/user-guide/kubectl/kubectl_replace.md @@ -75,6 +75,7 @@ kubectl replace --force -f ./pod.json --force[=false]: Delete and re-create the specified resource --grace-period=-1: Only relevant during a force replace. Period of time in seconds given to the old resource to terminate gracefully. Ignored if negative. -o, --output="": Output mode. Use "-o name" for shorter output (resource/name). + --record[=false]: Record current kubectl command in the resource annotation. --save-config[=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. --schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema' --timeout=0: Only relevant during a force replace. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object @@ -113,7 +114,7 @@ kubectl replace --force -f ./pod.json * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_replace.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_run.md b/docs/user-guide/kubectl/kubectl_run.md index 9b8a6f8ef8..56b49387d5 100644 --- a/docs/user-guide/kubectl/kubectl_run.md +++ b/docs/user-guide/kubectl/kubectl_run.md @@ -99,6 +99,7 @@ $ kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'pri --output-version="": Output the formatted object with the given version (default api-version). --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. --port=-1: The port that this container exposes. If --expose is true, this is also the port used by the service that is created. + --record[=false]: Record current kubectl command in the resource annotation. -r, --replicas=1: Number of replicas to create for this container. Default is 1. --requests="": The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi' --restart="Always": The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a replication controller is created for this pod, if set to OnFailure or Never, a job is created for this pod and --replicas must be 1. Default 'Always' @@ -145,7 +146,7 @@ $ kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'pri * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 14-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_run.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_scale.md b/docs/user-guide/kubectl/kubectl_scale.md index 77c820e905..61699354b8 100644 --- a/docs/user-guide/kubectl/kubectl_scale.md +++ b/docs/user-guide/kubectl/kubectl_scale.md @@ -75,6 +75,7 @@ $ kubectl scale --replicas=3 job/cron --current-replicas=-1: Precondition for current size. Requires that the current size of the resource match this value in order to scale. -f, --filename=[]: Filename, directory, or URL to a file identifying the resource to set a new size -o, --output="": Output mode. Use "-o name" for shorter output (resource/name). + --record[=false]: Record current kubectl command in the resource annotation. --replicas=-1: The new desired number of replicas. Required. --resource-version="": Precondition for resource version. Requires that the current resource version match this value in order to scale. --timeout=0: The length of time to wait before giving up on a scale operation, zero means don't wait. @@ -112,7 +113,7 @@ $ kubectl scale --replicas=3 job/cron * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 8-Dec-2015 +###### Auto generated by spf13/cobra on 22-Jan-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_scale.md?pixel)]() diff --git a/pkg/controller/deployment/deployment_controller.go b/pkg/controller/deployment/deployment_controller.go index 7b2a776a4e..0024378e66 100644 --- a/pkg/controller/deployment/deployment_controller.go +++ b/pkg/controller/deployment/deployment_controller.go @@ -34,6 +34,7 @@ import ( unversioned_legacy "k8s.io/kubernetes/pkg/client/typed/generated/legacy/unversioned" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/framework" + "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" deploymentutil "k8s.io/kubernetes/pkg/util/deployment" @@ -721,6 +722,12 @@ func (dc *DeploymentController) getNewRC(deployment extensions.Deployment, maxOl Template: &newRCTemplate, }, } + if _, ok := deployment.Annotations[kubectl.ChangeCauseAnnotation]; ok { + if newRC.Annotations == nil { + newRC.Annotations = make(map[string]string) + } + newRC.Annotations[kubectl.ChangeCauseAnnotation] = deployment.Annotations[kubectl.ChangeCauseAnnotation] + } createdRC, err := dc.client.Legacy().ReplicationControllers(namespace).Create(&newRC) if err != nil { dc.rcExpectations.DeleteExpectations(dKey) diff --git a/pkg/kubectl/cmd/annotate.go b/pkg/kubectl/cmd/annotate.go index 23ed867bb3..69921f9089 100644 --- a/pkg/kubectl/cmd/annotate.go +++ b/pkg/kubectl/cmd/annotate.go @@ -46,6 +46,9 @@ type AnnotateOptions struct { all bool resourceVersion string + changeCause string + recordFlag bool + f *cmdutil.Factory out io.Writer cmd *cobra.Command @@ -111,6 +114,7 @@ func NewCmdAnnotate(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.Flags().StringVar(&options.resourceVersion, "resource-version", "", "If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.") usage := "Filename, directory, or URL to a file identifying the resource to update the annotation" kubectl.AddJsonFilenameFlag(cmd, &options.filenames, usage) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -151,6 +155,9 @@ func (o *AnnotateOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra return err } + o.recordFlag = cmdutil.GetRecordFlag(cmd) + o.changeCause = f.Command() + mapper, typer := f.Object() o.builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). ContinueOnError(). @@ -199,6 +206,10 @@ func (o AnnotateOptions) RunAnnotate() error { if err != nil { return err } + // If we should record change-cause, add it to new annotations + if cmdutil.ContainsChangeCause(info) || o.recordFlag { + o.newAnnotations[kubectl.ChangeCauseAnnotation] = o.changeCause + } if err := o.updateAnnotations(obj); err != nil { return err } @@ -292,6 +303,10 @@ func validateAnnotations(removeAnnotations []string, newAnnotations map[string]s func validateNoAnnotationOverwrites(meta *api.ObjectMeta, annotations map[string]string) error { var buf bytes.Buffer for key := range annotations { + // change-cause annotation can always be overwritten + if key == kubectl.ChangeCauseAnnotation { + continue + } if value, found := meta.Annotations[key]; found { if buf.Len() > 0 { buf.WriteString("; ") diff --git a/pkg/kubectl/cmd/apply.go b/pkg/kubectl/cmd/apply.go index ef63b04009..89c6a6c1f6 100644 --- a/pkg/kubectl/cmd/apply.go +++ b/pkg/kubectl/cmd/apply.go @@ -69,6 +69,7 @@ func NewCmdApply(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.MarkFlagRequired("filename") cmdutil.AddValidateFlags(cmd) cmdutil.AddOutputFlagsForMutation(cmd) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -132,6 +133,13 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap if err := kubectl.CreateApplyAnnotation(info, encoder); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) } + + if cmdutil.ShouldRecord(cmd, info) { + if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil { + return cmdutil.AddSourceToErr("creating", info.Source, err) + } + } + // Then create the resource and skip the three-way merge if err := createAndRefresh(info); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) @@ -166,6 +174,17 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patch, info), info.Source, err) } + if cmdutil.ShouldRecord(cmd, info) { + patch, err = cmdutil.ChangeResourcePatch(info, f.Command()) + if err != nil { + return err + } + _, err = helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch) + if err != nil { + return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patch, info), info.Source, err) + } + } + count++ cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "configured") return nil diff --git a/pkg/kubectl/cmd/autoscale.go b/pkg/kubectl/cmd/autoscale.go index 6647db0118..343c3a8a55 100644 --- a/pkg/kubectl/cmd/autoscale.go +++ b/pkg/kubectl/cmd/autoscale.go @@ -64,6 +64,7 @@ func NewCmdAutoscale(f *cmdutil.Factory, out io.Writer) *cobra.Command { usage := "Filename, directory, or URL to a file identifying the resource to autoscale." kubectl.AddJsonFilenameFlag(cmd, &filenames, usage) cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -139,6 +140,12 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args [] if err != nil { return err } + if cmdutil.ShouldRecord(cmd, hpa) { + if err := cmdutil.RecordChangeCause(hpa.Object, f.Command()); err != nil { + return err + } + object = hpa.Object + } // TODO: extract this flag to a central location, when such a location exists. if cmdutil.GetFlagBool(cmd, "dry-run") { return f.PrintObject(cmd, object, out) diff --git a/pkg/kubectl/cmd/create.go b/pkg/kubectl/cmd/create.go index 10b30ba4ef..6c4061ea04 100644 --- a/pkg/kubectl/cmd/create.go +++ b/pkg/kubectl/cmd/create.go @@ -73,6 +73,7 @@ func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmdutil.AddValidateFlags(cmd) cmdutil.AddOutputFlagsForMutation(cmd) cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddRecordFlag(cmd) // create subcommands cmd.AddCommand(NewCmdCreateNamespace(f, out)) @@ -120,6 +121,12 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C return cmdutil.AddSourceToErr("creating", info.Source, err) } + if cmdutil.ShouldRecord(cmd, info) { + if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil { + return cmdutil.AddSourceToErr("creating", info.Source, err) + } + } + if err := createAndRefresh(info); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) } diff --git a/pkg/kubectl/cmd/edit.go b/pkg/kubectl/cmd/edit.go index e98407bf84..7543c4a0e5 100644 --- a/pkg/kubectl/cmd/edit.go +++ b/pkg/kubectl/cmd/edit.go @@ -97,6 +97,7 @@ func NewCmdEdit(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).") cmd.Flags().Bool("windows-line-endings", gruntime.GOOS == "windows", "Use Windows line-endings (default Unix line-endings)") cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -232,6 +233,12 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), updates, encoder); err != nil { return preservedFile(err, file, out) } + if cmdutil.ShouldRecord(cmd, updates) { + err = cmdutil.RecordChangeCause(updates.Object, f.Command()) + if err != nil { + return err + } + } // encode updates back to "edited" since we'll only generate patch from "edited" if edited, err = runtime.Encode(encoder, updates.Object); err != nil { return preservedFile(err, file, out) diff --git a/pkg/kubectl/cmd/expose.go b/pkg/kubectl/cmd/expose.go index 0546971316..a00d00eb5a 100644 --- a/pkg/kubectl/cmd/expose.go +++ b/pkg/kubectl/cmd/expose.go @@ -95,6 +95,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" kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -210,6 +211,12 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str if err != nil { return err } + if cmdutil.ShouldRecord(cmd, info) { + if err := cmdutil.RecordChangeCause(object, f.Command()); err != nil { + return err + } + } + info.Refresh(object, true) // TODO: extract this flag to a central location, when such a location exists. if cmdutil.GetFlagBool(cmd, "dry-run") { return f.PrintObject(cmd, object, out) diff --git a/pkg/kubectl/cmd/label.go b/pkg/kubectl/cmd/label.go index 8069d003f6..9e6d76edc2 100644 --- a/pkg/kubectl/cmd/label.go +++ b/pkg/kubectl/cmd/label.go @@ -97,6 +97,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" kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.") + cmdutil.AddRecordFlag(cmd) return cmd } @@ -252,6 +253,11 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri if err := labelFunc(obj, overwrite, resourceVersion, lbls, remove); err != nil { return err } + if cmdutil.ShouldRecord(cmd, info) { + if err := cmdutil.RecordChangeCause(obj, f.Command()); err != nil { + return err + } + } newData, err := json.Marshal(obj) if err != nil { return err diff --git a/pkg/kubectl/cmd/patch.go b/pkg/kubectl/cmd/patch.go index b537adaa18..9bce6f2088 100644 --- a/pkg/kubectl/cmd/patch.go +++ b/pkg/kubectl/cmd/patch.go @@ -70,6 +70,7 @@ func NewCmdPatch(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.") cmd.MarkFlagRequired("patch") cmdutil.AddOutputFlagsForMutation(cmd) + cmdutil.AddRecordFlag(cmd) usage := "Filename, directory, or URL to a file identifying the resource to update" kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) @@ -124,6 +125,16 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri if err != nil { return err } + if cmdutil.ShouldRecord(cmd, info) { + patchBytes, err = cmdutil.ChangeResourcePatch(info, f.Command()) + if err != nil { + return err + } + _, err = helper.Patch(namespace, name, api.StrategicMergePatchType, patchBytes) + if err != nil { + return err + } + } cmdutil.PrintSuccess(mapper, shortOutput, out, "", name, "patched") return nil } diff --git a/pkg/kubectl/cmd/replace.go b/pkg/kubectl/cmd/replace.go index 226e5c434d..81eacecbd4 100644 --- a/pkg/kubectl/cmd/replace.go +++ b/pkg/kubectl/cmd/replace.go @@ -84,6 +84,7 @@ func NewCmdReplace(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmdutil.AddValidateFlags(cmd) cmdutil.AddOutputFlagsForMutation(cmd) cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -133,6 +134,12 @@ func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st return cmdutil.AddSourceToErr("replacing", info.Source, err) } + if cmdutil.ShouldRecord(cmd, info) { + if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil { + return cmdutil.AddSourceToErr("replacing", info.Source, err) + } + } + // Serialize the object with the annotation applied. obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object) if err != nil { @@ -220,6 +227,12 @@ func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args [] return err } + if cmdutil.ShouldRecord(cmd, info) { + if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil { + return cmdutil.AddSourceToErr("replacing", info.Source, err) + } + } + obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object) if err != nil { return err diff --git a/pkg/kubectl/cmd/run.go b/pkg/kubectl/cmd/run.go index e7804bc9de..78aba15383 100644 --- a/pkg/kubectl/cmd/run.go +++ b/pkg/kubectl/cmd/run.go @@ -83,6 +83,7 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c cmdutil.AddPrinterFlags(cmd) addRunFlags(cmd) cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddRecordFlag(cmd) return cmd } @@ -425,6 +426,15 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub return nil, "", nil, nil, err } + annotations, err := mapping.MetadataAccessor.Annotations(obj) + if err != nil { + return nil, "", nil, nil, err + } + if cmdutil.GetRecordFlag(cmd) || len(annotations[kubectl.ChangeCauseAnnotation]) > 0 { + if err := cmdutil.RecordChangeCause(obj, f.Command()); err != nil { + return nil, "", nil, nil, err + } + } // TODO: extract this flag to a central location, when such a location exists. if !cmdutil.GetFlagBool(cmd, "dry-run") { resourceMapper := &resource.Mapper{ diff --git a/pkg/kubectl/cmd/run_test.go b/pkg/kubectl/cmd/run_test.go index 520c7de30d..8f7ebedbf0 100644 --- a/pkg/kubectl/cmd/run_test.go +++ b/pkg/kubectl/cmd/run_test.go @@ -300,6 +300,7 @@ func TestGenerateService(t *testing.T) { cmd := &cobra.Command{} cmd.Flags().String("output", "", "") cmd.Flags().Bool(cmdutil.ApplyAnnotationsFlag, false, "") + cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation.") addRunFlags(cmd) if !test.expectPOST { diff --git a/pkg/kubectl/cmd/scale.go b/pkg/kubectl/cmd/scale.go index 2637fa2b0a..6ffd435661 100644 --- a/pkg/kubectl/cmd/scale.go +++ b/pkg/kubectl/cmd/scale.go @@ -23,6 +23,7 @@ import ( "github.com/spf13/cobra" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/kubectl" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" @@ -82,6 +83,7 @@ func NewCmdScale(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.MarkFlagRequired("replicas") cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a scale operation, zero means don't wait.") cmdutil.AddOutputFlagsForMutation(cmd) + cmdutil.AddRecordFlag(cmd) usage := "Filename, directory, or URL to a file identifying the resource to set a new size" kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) @@ -149,6 +151,24 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri errs = append(errs, err) continue } + if cmdutil.ShouldRecord(cmd, info) { + patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command()) + if err != nil { + errs = append(errs, err) + continue + } + mapping := info.ResourceMapping() + client, err := f.ClientForMapping(mapping) + if err != nil { + return err + } + helper := resource.NewHelper(client, mapping) + _, err = helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patchBytes) + if err != nil { + errs = append(errs, err) + continue + } + } cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "scaled") } diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index eea080f537..283254f86f 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -27,6 +27,7 @@ import ( "os/user" "path" "strconv" + "strings" "time" "github.com/emicklei/go-restful/swagger" @@ -62,6 +63,7 @@ const ( type Factory struct { clients *ClientCache flags *pflag.FlagSet + cmd string // Returns interfaces for dealing with arbitrary runtime.Objects. Object func() (meta.RESTMapper, runtime.ObjectTyper) @@ -182,6 +184,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { return &Factory{ clients: clients, flags: flags, + cmd: recordCommand(os.Args), Object: func() (meta.RESTMapper, runtime.ObjectTyper) { cfg, err := clientConfig.ClientConfig() @@ -472,6 +475,17 @@ func GetFirstPod(client *client.Client, namespace string, selector map[string]st return pod, nil } +func recordCommand(args []string) string { + if len(args) > 0 { + args[0] = "kubectl" + } + return strings.Join(args, " ") +} + +func (f *Factory) Command() string { + return f.cmd +} + // BindFlags adds any flags that are common to all kubectl sub commands. func (f *Factory) BindFlags(flags *pflag.FlagSet) { // any flags defined by external projects (not part of pflags) diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go index d5705b4abd..19cc401e7d 100644 --- a/pkg/kubectl/cmd/util/helpers.go +++ b/pkg/kubectl/cmd/util/helpers.go @@ -18,6 +18,7 @@ package util import ( "bytes" + "encoding/json" "fmt" "io" "io/ioutil" @@ -27,6 +28,7 @@ import ( "strings" "time" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" @@ -34,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/runtime" utilerrors "k8s.io/kubernetes/pkg/util/errors" + "k8s.io/kubernetes/pkg/util/strategicpatch" "github.com/evanphx/json-patch" "github.com/golang/glog" @@ -434,3 +437,56 @@ func UpdateObject(info *resource.Info, codec runtime.Codec, updateFn func(runtim return info.Object, nil } + +// AddCmdRecordFlag adds --record flag to command +func AddRecordFlag(cmd *cobra.Command) { + cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation.") +} + +func GetRecordFlag(cmd *cobra.Command) bool { + return GetFlagBool(cmd, "record") +} + +// RecordChangeCause annotate change-cause to input runtime object. +func RecordChangeCause(obj runtime.Object, changeCause string) error { + meta, err := api.ObjectMetaFor(obj) + if err != nil { + return err + } + if meta.Annotations == nil { + meta.Annotations = make(map[string]string) + } + meta.Annotations[kubectl.ChangeCauseAnnotation] = changeCause + return nil +} + +// ChangeResourcePatch creates a strategic merge patch between the origin input resource info +// and the annotated with change-cause input resource info. +func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, error) { + oldData, err := json.Marshal(info.Object) + if err != nil { + return nil, err + } + if err := RecordChangeCause(info.Object, changeCause); err != nil { + return nil, err + } + newData, err := json.Marshal(info.Object) + if err != nil { + return nil, err + } + return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object) +} + +// containsChangeCause checks if input resource info contains change-cause annotation. +func ContainsChangeCause(info *resource.Info) bool { + annotations, err := info.Mapping.MetadataAccessor.Annotations(info.Object) + if err != nil { + return false + } + return len(annotations[kubectl.ChangeCauseAnnotation]) > 0 +} + +// ShouldRecord checks if we should record current change cause +func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool { + return GetRecordFlag(cmd) || ContainsChangeCause(info) +}