Compare commits

..

2 Commits

Author SHA1 Message Date
Kubernetes Publisher 15730f30ee Update dependencies to v0.32.0-rc.1 tag 2024-12-03 23:34:24 +00:00
Kubernetes Publisher e8e0a12f5e Merge pull request #128559 from lauralorenz/crashloopbackoff-refactorimagepullbackoff-e2enodecriproxytest
E2E Node tests for image pull backoff and crashloopbackoff behavior

Kubernetes-commit: 5ee686b6cfd1431dbde77873f64d9c2a90610745
2024-11-27 21:16:12 +00:00
135 changed files with 593 additions and 8583 deletions

View File

@ -10,7 +10,7 @@
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
ardaguclu
eddiezane
mpuckett159
KnVerey
natasha41575
soltysh

2
doc.go
View File

@ -14,4 +14,4 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package kubectl
package kubectl // import "k8s.io/kubectl"

85
go.mod
View File

@ -2,9 +2,9 @@
module k8s.io/kubectl
go 1.24.0
go 1.23.0
godebug default=go1.24
godebug default=go1.23
require (
github.com/MakeNowJust/heredoc v1.0.0
@ -13,57 +13,58 @@ require (
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f
github.com/fatih/camelcase v1.0.0
github.com/go-openapi/jsonreference v0.20.2
github.com/google/gnostic-models v0.7.0
github.com/google/go-cmp v0.7.0
github.com/jonboulle/clockwork v0.5.0
github.com/google/gnostic-models v0.6.8
github.com/google/go-cmp v0.6.0
github.com/jonboulle/clockwork v0.4.0
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
github.com/lithammer/dedent v1.1.0
github.com/mitchellh/go-wordwrap v1.0.1
github.com/moby/term v0.5.0
github.com/onsi/ginkgo/v2 v2.21.0
github.com/onsi/gomega v1.35.1
github.com/pkg/errors v0.9.1
github.com/russross/blackfriday/v2 v2.1.0
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
go.yaml.in/yaml/v2 v2.4.2
golang.org/x/sys v0.31.0
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
golang.org/x/sys v0.26.0
gopkg.in/evanphx/json-patch.v4 v4.12.0
k8s.io/api v0.0.0-20250718010531-33ab3a26f4b3
k8s.io/apimachinery v0.0.0-20250717210244-b92abb2d8139
k8s.io/cli-runtime v0.0.0-20250717174531-64776d0a280f
k8s.io/client-go v0.0.0-20250718010928-be36413bbca7
k8s.io/component-base v0.0.0-20250717172125-4e07767df717
k8s.io/component-helpers v0.0.0-20250717172249-5095859f5100
k8s.io/api v0.32.0-rc.1
k8s.io/apimachinery v0.32.0-rc.1
k8s.io/cli-runtime v0.32.0-rc.1
k8s.io/client-go v0.32.0-rc.1
k8s.io/component-base v0.32.0-rc.1
k8s.io/component-helpers v0.32.0-rc.1
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
k8s.io/metrics v0.0.0-20250717174355-244095fcc1c1
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8
sigs.k8s.io/kustomize/kustomize/v5 v5.6.0
sigs.k8s.io/kustomize/kyaml v0.19.0
sigs.k8s.io/randfill v1.0.0
sigs.k8s.io/structured-merge-diff/v6 v6.3.0
sigs.k8s.io/yaml v1.5.0
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f
k8s.io/metrics v0.32.0-rc.1
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3
sigs.k8s.io/kustomize/kustomize/v5 v5.5.0
sigs.k8s.io/kustomize/kyaml v0.18.1
sigs.k8s.io/structured-merge-diff/v4 v4.4.2
sigs.k8s.io/yaml v1.4.0
)
require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
@ -71,28 +72,24 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/oauth2 v0.27.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/kustomize/api v0.19.0 // indirect
sigs.k8s.io/kustomize/api v0.18.0 // indirect
)
replace k8s.io/code-generator => k8s.io/code-generator v0.0.0-20250718051115-9eb96548a40e

158
go.sum
View File

@ -8,23 +8,24 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@ -41,27 +42,32 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -90,9 +96,8 @@ github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@ -109,18 +114,19 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -132,8 +138,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
@ -142,10 +148,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -155,29 +157,29 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -188,8 +190,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@ -200,37 +202,35 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.0.0-20250718010531-33ab3a26f4b3 h1:UnuyCQyBmdFlYypApF2w6Ld0R0kAt8b+0Lt9dYAr23I=
k8s.io/api v0.0.0-20250718010531-33ab3a26f4b3/go.mod h1:K8dwhtttsRR0RHeSRF8XQ77gfMgyAj3q78/TkxEXhoc=
k8s.io/apimachinery v0.0.0-20250717210244-b92abb2d8139 h1:jWBClrBPuk+GEA9pJzMa9IvxncSBbw7fmvey15nVm0w=
k8s.io/apimachinery v0.0.0-20250717210244-b92abb2d8139/go.mod h1:v1p1Jsze3IHLy5gU17yVqR2qLO7jgYeX6mw3HZy2AEU=
k8s.io/cli-runtime v0.0.0-20250717174531-64776d0a280f h1:E/GB1lzzKbz3HPJ6Zu1bJYrey6oDAIAA+RMEozCpPpU=
k8s.io/cli-runtime v0.0.0-20250717174531-64776d0a280f/go.mod h1:SybB6wdHGt8FXxaHyNQqsUAhWcZKIDPurWPB5mfFLD0=
k8s.io/client-go v0.0.0-20250718010928-be36413bbca7 h1:LNOJkn+3JlAEzdZzYheQM97gq6kKQfkrBN0GikI5nbc=
k8s.io/client-go v0.0.0-20250718010928-be36413bbca7/go.mod h1:a14VvgYhux7oUSE9mWdzBuFKDZSGtperboMjQ1JtVgc=
k8s.io/component-base v0.0.0-20250717172125-4e07767df717 h1:07oqkM0FzuGUw/bJw2rJubzccG7ShpGcTJ7SBDGp5Fc=
k8s.io/component-base v0.0.0-20250717172125-4e07767df717/go.mod h1:/ehREU84M2OxVgU8WfxuUIi4/c5XsT6rIsEGQfhgxEQ=
k8s.io/component-helpers v0.0.0-20250717172249-5095859f5100 h1:XEHmjwZgMNRuVgpqaRH/RR+n4BU0evfitU0RpWGPMUM=
k8s.io/component-helpers v0.0.0-20250717172249-5095859f5100/go.mod h1:yxuY+YMknW7H9Bj7B29INyMOacJBa6oEG7gi7IKUzEQ=
k8s.io/api v0.32.0-rc.1 h1:dxXiVjLYq4JmlXFgctsK9zJaXhPA1hJLO772lHk4wKw=
k8s.io/api v0.32.0-rc.1/go.mod h1:3TNYUV1WB3ZF2yOeY4qlr9FDb1GVzO+OucsXW2BOi5o=
k8s.io/apimachinery v0.32.0-rc.1 h1:jeLQr/Dqcq0kGU/yjEmievDMHTJzzwQctlysW0Kb70U=
k8s.io/apimachinery v0.32.0-rc.1/go.mod h1:HqhdaJUgQqky29T1V0o2yFkt/pZqLFIDyn9Zi/8rxoY=
k8s.io/cli-runtime v0.32.0-rc.1 h1:rQDtu2ihnv/ItkawGIewwqhgb6C6skVwNFWCxBx7loI=
k8s.io/cli-runtime v0.32.0-rc.1/go.mod h1:ifV1UrGAvsFhohEfFLkxoAAZPAXnp92ROioZvFG4be4=
k8s.io/client-go v0.32.0-rc.1 h1:ZW27sbQZ06FnkFTNqlfa9HTIW01RGoLoiOmdiLbWYK0=
k8s.io/client-go v0.32.0-rc.1/go.mod h1:Nlv9GR11bKYSlCcxY3B1RpVbcsfasSAwminv42knDHk=
k8s.io/component-base v0.32.0-rc.1 h1:c3EG8QuyozbalRmbsUxXW/ZmF2bev3Zq9PbpU3oIHT4=
k8s.io/component-base v0.32.0-rc.1/go.mod h1:xIvfPkeLsQbd2fkDNWezG20WQwrabBetTUxp67eycbI=
k8s.io/component-helpers v0.32.0-rc.1 h1:bMxK0t94aurgt9vF5M4XhtF8crRJtbKdNJPJleX+zG8=
k8s.io/component-helpers v0.32.0-rc.1/go.mod h1:PQV0gdYXBikdjJkxiBLZTsnt/Z9QCMoc9yIT3eJ6PGw=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/metrics v0.0.0-20250717174355-244095fcc1c1 h1:V4I6U/hfhZYYmDotL7ukG0nua1luMQSox5QtveZaSv0=
k8s.io/metrics v0.0.0-20250717174355-244095fcc1c1/go.mod h1:TkHVkU+vMKy7qppbMybraSCK8Y+LLpoqk/6Jl+M8EoU=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
sigs.k8s.io/kustomize/kustomize/v5 v5.6.0 h1:MWtRRDWCwQEeW2rnJTqJMuV6Agy56P53SkbVoJpN7wA=
sigs.k8s.io/kustomize/kustomize/v5 v5.6.0/go.mod h1:XuuZiQF7WdcvZzEYyNww9A0p3LazCKeJmCjeycN8e1I=
sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
k8s.io/metrics v0.32.0-rc.1 h1:vXJA6ZRQOm4R1TIOI3UsZ9Hy8A1hexgqiHvV2PtzCa8=
k8s.io/metrics v0.32.0-rc.1/go.mod h1:tI5KTDENZAT3j3yaWHID+fTJp/HcAGqum94vuLMuCrY=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo=
sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U=
sigs.k8s.io/kustomize/kustomize/v5 v5.5.0 h1:o1mtt6vpxsxDYaZKrw3BnEtc+pAjLz7UffnIvHNbvW0=
sigs.k8s.io/kustomize/kustomize/v5 v5.5.0/go.mod h1:AeFCmgCrXzmvjWWaeZCyBp6XzG1Y0w1svYus8GhJEOE=
sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E=
sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -123,11 +123,11 @@ func NewCmdAPIResources(restClientGetter genericclioptions.RESTClientGetter, ioS
// Validate checks to the APIResourceOptions to see if there is sufficient information run the command
func (o *APIResourceOptions) Validate() error {
supportedOutputTypes := sets.New[string]("", "wide", "name")
supportedOutputTypes := sets.NewString("", "wide", "name")
if !supportedOutputTypes.Has(o.Output) {
return fmt.Errorf("--output %v is not available", o.Output)
}
supportedSortTypes := sets.New[string]("", "name", "kind")
supportedSortTypes := sets.NewString("", "name", "kind")
if len(o.SortBy) > 0 {
if !supportedSortTypes.Has(o.SortBy) {
return fmt.Errorf("--sort-by accepts only name or kind")
@ -193,11 +193,11 @@ func (o *APIResourceOptions) RunAPIResources() error {
continue
}
// filter to resources that support the specified verbs
if len(o.Verbs) > 0 && !sets.New[string](resource.Verbs...).HasAll(o.Verbs...) {
if len(o.Verbs) > 0 && !sets.NewString(resource.Verbs...).HasAll(o.Verbs...) {
continue
}
// filter to resources that belong to the specified categories
if len(o.Categories) > 0 && !sets.New[string](resource.Categories...).HasAll(o.Categories...) {
if len(o.Categories) > 0 && !sets.NewString(resource.Categories...).HasAll(o.Categories...) {
continue
}
resources = append(resources, groupResource{

View File

@ -23,7 +23,7 @@ import (
"net/http"
"github.com/spf13/cobra"
"sigs.k8s.io/structured-merge-diff/v6/fieldpath"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"

View File

@ -2605,6 +2605,7 @@ metadata:
applyset.kubernetes.io/additional-namespaces: ""
applyset.kubernetes.io/contains-group-kinds: ReplicationController
applyset.kubernetes.io/tooling: kubectl/v0.0.0-master+$Format:%H$
creationTimestamp: null
labels:
applyset.kubernetes.io/id: applyset-0eFHV8ySqp7XoShsGvyWFQD3s96yqwHmzc4e0HR1dsY-v1
name: my-set
@ -2638,6 +2639,7 @@ metadata:
applyset.kubernetes.io/additional-namespaces: ""
applyset.kubernetes.io/contains-group-kinds: ReplicationController,Service
applyset.kubernetes.io/tooling: kubectl/v0.0.0-master+$Format:%H$
creationTimestamp: null
labels:
applyset.kubernetes.io/id: applyset-0eFHV8ySqp7XoShsGvyWFQD3s96yqwHmzc4e0HR1dsY-v1
name: my-set
@ -2672,6 +2674,7 @@ metadata:
applyset.kubernetes.io/additional-namespaces: ""
applyset.kubernetes.io/contains-group-kinds: ReplicationController,Service
applyset.kubernetes.io/tooling: kubectl/v0.0.0-master+$Format:%H$
creationTimestamp: null
labels:
applyset.kubernetes.io/id: applyset-0eFHV8ySqp7XoShsGvyWFQD3s96yqwHmzc4e0HR1dsY-v1
name: my-set
@ -2706,6 +2709,7 @@ metadata:
applyset.kubernetes.io/additional-namespaces: ""
applyset.kubernetes.io/contains-group-kinds: Service
applyset.kubernetes.io/tooling: kubectl/v0.0.0-master+$Format:%H$
creationTimestamp: null
labels:
applyset.kubernetes.io/id: applyset-0eFHV8ySqp7XoShsGvyWFQD3s96yqwHmzc4e0HR1dsY-v1
name: my-set
@ -2868,6 +2872,7 @@ metadata:
applyset.kubernetes.io/additional-namespaces: test
applyset.kubernetes.io/contains-group-kinds: ReplicationController
applyset.kubernetes.io/tooling: kubectl/v0.0.0-master+$Format:%H$
creationTimestamp: null
labels:
applyset.kubernetes.io/id: applyset-rhp1a-HVAVT_dFgyEygyA1BEB82HPp2o10UiFTpqtAs-v1
name: my-set
@ -3085,6 +3090,7 @@ metadata:
applyset.kubernetes.io/additional-namespaces: ""
applyset.kubernetes.io/contains-group-resources: replicationcontrollers
applyset.kubernetes.io/tooling: kubectl/v0.0.0-master+$Format:%H$
creationTimestamp: null
labels:
applyset.kubernetes.io/id: applyset-0eFHV8ySqp7XoShsGvyWFQD3s96yqwHmzc4e0HR1dsY-v1
name: my-set

View File

@ -23,6 +23,8 @@ import (
"io"
"time"
"github.com/pkg/errors"
"github.com/jonboulle/clockwork"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@ -59,7 +61,7 @@ const (
// patchRetryBackOffPeriod is the period to back off when apply patch results in error.
var patchRetryBackOffPeriod = 1 * time.Second
var createPatchErrFormat = "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor: %w"
var createPatchErrFormat = "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
// Patcher defines options to patch OpenAPI objects.
type Patcher struct {
@ -118,13 +120,13 @@ func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, namespace, na
// Serialize the current configuration of the object from the server.
current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
if err != nil {
return nil, nil, fmt.Errorf("serializing current configuration from:\n%v\nfor: %w", obj, err)
return nil, nil, errors.Wrapf(err, "serializing current configuration from:\n%v\nfor:", obj)
}
// Retrieve the original configuration of the object from the annotation.
original, err := util.GetOriginalConfiguration(obj)
if err != nil {
return nil, nil, fmt.Errorf("retrieving original configuration from:\n%v\nfor: %w", obj, err)
return nil, nil, errors.Wrapf(err, "retrieving original configuration from:\n%v\nfor:", obj)
}
var patchType types.PatchType
@ -176,17 +178,17 @@ func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, namespace, na
patchType = types.StrategicMergePatchType
patch, err = p.buildStrategicMergeFromBuiltins(versionedObj, original, modified, current)
if err != nil {
return nil, nil, fmt.Errorf(createPatchErrFormat, original, modified, current, err)
return nil, nil, errors.Wrapf(err, createPatchErrFormat, original, modified, current)
}
} else {
if !runtime.IsNotRegisteredError(err) {
return nil, nil, fmt.Errorf("getting instance of versioned object for %v: %w", p.Mapping.GroupVersionKind, err)
return nil, nil, errors.Wrapf(err, "getting instance of versioned object for %v:", p.Mapping.GroupVersionKind)
}
patchType = types.MergePatchType
patch, err = p.buildMergePatch(original, modified, current)
if err != nil {
return nil, nil, fmt.Errorf(createPatchErrFormat, original, modified, current, err)
return nil, nil, errors.Wrapf(err, createPatchErrFormat, original, modified, current)
}
}
}
@ -198,7 +200,7 @@ func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, namespace, na
if p.ResourceVersion != nil {
patch, err = addResourceVersion(patch, *p.ResourceVersion)
if err != nil {
return nil, nil, fmt.Errorf("failed to insert resourceVersion in patch: %w", err)
return nil, nil, errors.Wrap(err, "Failed to insert resourceVersion in patch")
}
}

View File

@ -307,7 +307,6 @@ func (o *AttachOptions) Run() error {
}
if !o.Quiet {
_, _ = fmt.Fprintln(o.ErrOut, "All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.")
fmt.Fprintln(o.ErrOut, "If you don't see a command prompt, try pressing enter.")
}
if err := t.Safe(o.AttachFunc(o, containerToAttach, t.Raw, sizeQueue)); err != nil {

View File

@ -242,7 +242,6 @@ func TestAttach(t *testing.T) {
pod *corev1.Pod
remoteAttachErr bool
expectedErr string
expectedErrOut []string
}{
{
name: "pod attach",
@ -252,10 +251,6 @@ func TestAttach(t *testing.T) {
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
container: "bar",
expectedErrOut: []string{
"All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.",
"If you don't see a command prompt, try pressing enter.",
},
},
{
name: "pod attach error",
@ -310,11 +305,10 @@ func TestAttach(t *testing.T) {
if test.remoteAttachErr {
remoteAttach.err = fmt.Errorf("attach error")
}
streams, _, _, errOut := genericiooptions.NewTestIOStreams()
options := &AttachOptions{
StreamOptions: exec.StreamOptions{
ContainerName: test.container,
IOStreams: streams,
IOStreams: genericiooptions.NewTestIOStreamsDiscard(),
},
Attach: remoteAttach,
GetPodTimeout: 1000,
@ -355,14 +349,6 @@ func TestAttach(t *testing.T) {
if remoteAttach.url.Query().Get("container") != "bar" {
t.Errorf("%s: Did not have query parameters: %s", test.name, remoteAttach.url.Query())
}
if test.expectedErrOut != nil {
for _, expect := range test.expectedErrOut {
if !strings.Contains(errOut.String(), expect) {
t.Errorf("%s: expected message %s not found, got: %s", test.name, expect, strings.ReplaceAll(errOut.String(), "\n", ""))
return
}
}
}
})
}
}

View File

@ -105,10 +105,10 @@ var (
# List all allowed actions in namespace "foo"
kubectl auth can-i --list --namespace=foo`)
resourceVerbs = sets.New[string]("get", "list", "watch", "create", "update", "patch", "delete", "deletecollection", "use", "bind", "impersonate", "*", "approve", "sign", "escalate", "attest")
nonResourceURLVerbs = sets.New[string]("get", "put", "post", "head", "options", "delete", "patch", "*")
resourceVerbs = sets.NewString("get", "list", "watch", "create", "update", "patch", "delete", "deletecollection", "use", "bind", "impersonate", "*", "approve", "sign", "escalate", "attest")
nonResourceURLVerbs = sets.NewString("get", "put", "post", "head", "options", "delete", "patch", "*")
// holds all the server-supported resources that cannot be discovered by clients. i.e. users and groups for the impersonate verb
nonStandardResourceNames = sets.New[string]("users", "groups")
nonStandardResourceNames = sets.NewString("users", "groups")
)
// NewCmdCanI returns an initialized Command for 'auth can-i' sub command

View File

@ -250,7 +250,7 @@ func printTableSelfSubjectAccessReview(obj runtime.Object, out io.Writer) error
}
if len(ui.Extra) > 0 {
for _, k := range sets.List(sets.KeySet(ui.Extra)) {
for _, k := range sets.StringKeySet(ui.Extra).List() {
v := ui.Extra[k]
_, err := fmt.Fprintf(w, "Extra: %s\t%v\n", k, v)
if err != nil {

View File

@ -75,7 +75,9 @@ func TestWhoAmIRun(t *testing.T) {
`{
"kind": "SelfSubjectReview",
"apiVersion": "authentication.k8s.io/v1",
"metadata": {},
"metadata": {
"creationTimestamp": null
},
"status": {
"userInfo": {
"username": "jane.doe",
@ -129,7 +131,9 @@ func TestWhoAmIRun(t *testing.T) {
`{
"kind": "SelfSubjectReview",
"apiVersion": "authentication.k8s.io/v1beta1",
"metadata": {},
"metadata": {
"creationTimestamp": null
},
"status": {
"userInfo": {
"username": "jane.doe",
@ -182,7 +186,9 @@ func TestWhoAmIRun(t *testing.T) {
`{
"kind": "SelfSubjectReview",
"apiVersion": "authentication.k8s.io/v1",
"metadata": {},
"metadata": {
"creationTimestamp": null
},
"status": {
"userInfo": {
"username": "jane.doe",

View File

@ -19,26 +19,19 @@ package autoscale
import (
"context"
"fmt"
"strconv"
"strings"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
apiresource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
autoscalingv2client "k8s.io/client-go/kubernetes/typed/autoscaling/v2"
"k8s.io/client-go/scale"
"k8s.io/klog/v2"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
@ -50,23 +43,16 @@ import (
var (
autoscaleLong = templates.LongDesc(i18n.T(`
Creates an autoscaler that automatically chooses and sets the number of pods that run in a Kubernetes cluster.
The command will attempt to use the autoscaling/v2 API first, in case of an error, it will fall back to autoscaling/v1 API.
Looks up a deployment, replica set, stateful set, or replication controller by name and creates an autoscaler that uses the given resource as a reference.
An autoscaler can automatically increase or decrease number of pods deployed within the system as needed.`))
autoscaleExample = templates.Examples(i18n.T(`
# Auto scale a deployment "foo", with the number of pods between 2 and 10, no target CPU utilization specified so a default autoscaling policy will be used
kubectl autoscale deployment foo --min=2 --max=10
kubectl autoscale deployment foo --min=2 --max=10
# Auto scale a replication controller "foo", with the number of pods between 1 and 5, target CPU utilization at 80%
kubectl autoscale rc foo --max=5 --cpu=80%
# Auto scale a deployment "bar", with the number of pods between 3 and 6, target average CPU of 500m and memory of 200Mi
kubectl autoscale deployment bar --min=3 --max=6 --cpu=500m --memory=200Mi
# Auto scale a deployment "bar", with the number of pods between 2 and 8, target CPU utilization 60% and memory utilization 70%
kubectl autoscale deployment bar --min=3 --max=6 --cpu=60% --memory=70%`))
kubectl autoscale rc foo --max=5 --cpu-percent=80`))
)
// AutoscaleOptions declares the arguments accepted by the Autoscale command
@ -83,8 +69,6 @@ type AutoscaleOptions struct {
Min int32
Max int32
CPUPercent int32
CPU string
Memory string
createAnnotation bool
args []string
@ -94,8 +78,7 @@ type AutoscaleOptions struct {
builder *resource.Builder
fieldManager string
HPAClientV1 autoscalingv1client.HorizontalPodAutoscalersGetter
HPAClientV2 autoscalingv2client.HorizontalPodAutoscalersGetter
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
scaleKindResolver scale.ScaleKindResolver
genericiooptions.IOStreams
@ -120,7 +103,7 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *c
validArgs := []string{"deployment", "replicaset", "replicationcontroller", "statefulset"}
cmd := &cobra.Command{
Use: "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu=CPU] [--memory=MEMORY]",
Use: "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]",
DisableFlagsInUseLine: true,
Short: i18n.T("Auto-scale a deployment, replica set, stateful set, or replication controller"),
Long: autoscaleLong,
@ -140,11 +123,7 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *c
cmd.Flags().Int32Var(&o.Max, "max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
cmd.MarkFlagRequired("max")
cmd.Flags().Int32Var(&o.CPUPercent, "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, a default autoscaling policy will be used.")
cmd.Flags().StringVar(&o.CPU, "cpu", "", `Target CPU utilization over all the pods. When specified as a percentage (e.g."70%" for 70% of requested CPU) it will target average utilization. When specified as quantity (e.g."500m" for 500 milliCPU) it will target average value. Value without units is treated as a quantity with miliCPU being the unit (e.g."500" is "500m").`)
cmd.Flags().StringVar(&o.Memory, "memory", "", `Target memory utilization over all the pods. When specified as a percentage (e.g."60%" for 60% of requested memory) it will target average utilization. When specified as quantity (e.g."200Mi" for 200 MiB, "1Gi" for 1 GiB) it will target average value. Value without units is treated as a quantity with mebibytes being the unit (e.g."200" is "200Mi").`)
cmd.Flags().StringVar(&o.Name, "name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
_ = cmd.Flags().MarkDeprecated("cpu-percent",
"Use --cpu with percentage or resource quantity format (e.g., '70%' for utilization or '500m' for milliCPU).")
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to autoscale.")
cmdutil.AddApplyAnnotationFlags(cmd)
@ -178,8 +157,7 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
if err != nil {
return err
}
o.HPAClientV2 = kubeClient.AutoscalingV2()
o.HPAClientV1 = kubeClient.AutoscalingV1()
o.HPAClient = kubeClient.AutoscalingV1()
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
@ -204,25 +182,11 @@ func (o *AutoscaleOptions) Validate() error {
if o.Max < o.Min {
return fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", o.Max, o.Min)
}
// only one of the CPUPercent or CPU param is allowed
if o.CPUPercent > 0 && o.CPU != "" {
return fmt.Errorf("--cpu-percent and --cpu are mutually exclusive")
}
// validate CPU target if specified
if o.CPU != "" {
if _, _, _, err := parseResourceInput(o.CPU, corev1.ResourceCPU); err != nil {
return err
}
}
// validate Memory target if specified
if o.Memory != "" {
if _, _, _, err := parseResourceInput(o.Memory, corev1.ResourceMemory); err != nil {
return err
}
}
return nil
}
// Run performs the execution
func (o *AutoscaleOptions) Run() error {
r := o.builder.
Unstructured().
@ -244,31 +208,48 @@ func (o *AutoscaleOptions) Run() error {
mapping := info.ResourceMapping()
gvr := mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource.Resource)
if _, err = o.scaleKindResolver.ScaleForResource(gvr); err != nil {
return fmt.Errorf("cannot autoscale a %s: %w", mapping.GroupVersionKind.Kind, err)
if _, err := o.scaleKindResolver.ScaleForResource(gvr); err != nil {
return fmt.Errorf("cannot autoscale a %v: %v", mapping.GroupVersionKind.Kind, err)
}
// handles the creation of HorizontalPodAutoscaler objects for both autoscaling/v2 and autoscaling/v1 APIs.
// If autoscaling/v2 API fails, try to create and handle HorizontalPodAutoscaler using autoscaling/v1 API
var hpaV2 runtime.Object
hpaV2, err = o.createHorizontalPodAutoscalerV2(info.Name, mapping)
if err != nil {
return fmt.Errorf("failed to create HorizontalPodAutoscaler using autoscaling/v2 API: %w", err)
hpa := o.createHorizontalPodAutoscaler(info.Name, mapping)
if err := o.Recorder.Record(hpa); err != nil {
klog.V(4).Infof("error recording current command: %v", err)
}
if err = o.handleHPA(hpaV2); err != nil {
klog.V(1).Infof("Encountered an error with the autoscaling/v2 HorizontalPodAutoscaler: %v. "+
"Falling back to try the autoscaling/v1 HorizontalPodAutoscaler", err)
// check if the HPA can be created using v1 API.
if ok, err := o.canCreateHPAV1(); !ok {
return fmt.Errorf("failed to create autoscaling/v2 HPA and the configuration is incompatible with autoscaling/v1: %w", err)
}
hpaV1 := o.createHorizontalPodAutoscalerV1(info.Name, mapping)
if err := o.handleHPA(hpaV1); err != nil {
if o.dryRunStrategy == cmdutil.DryRunClient {
count++
printer, err := o.ToPrinter("created")
if err != nil {
return err
}
return printer.PrintObj(hpa, o.Out)
}
if err := util.CreateOrUpdateAnnotation(o.createAnnotation, hpa, scheme.DefaultJSONEncoder()); err != nil {
return err
}
createOptions := metav1.CreateOptions{}
if o.fieldManager != "" {
createOptions.FieldManager = o.fieldManager
}
if o.dryRunStrategy == cmdutil.DryRunServer {
createOptions.DryRun = []string{metav1.DryRunAll}
}
actualHPA, err := o.HPAClient.HorizontalPodAutoscalers(o.namespace).Create(context.TODO(), hpa, createOptions)
if err != nil {
return err
}
count++
return nil
printer, err := o.ToPrinter("autoscaled")
if err != nil {
return err
}
return printer.PrintObj(actualHPA, o.Out)
})
if err != nil {
return err
@ -279,169 +260,7 @@ func (o *AutoscaleOptions) Run() error {
return nil
}
func (o *AutoscaleOptions) canCreateHPAV1() (bool, error) {
// Allow fallback to v1 HPA only if:
// 1. CPUPercent is set and Memory is not set.
// 2. Or, Memory is not set and the metric type is UtilizationMetricType.
_, _, metricsType, err := parseResourceInput(o.CPU, corev1.ResourceCPU)
if err != nil {
return false, err
}
return (o.CPUPercent >= 0 && o.Memory == "") ||
(o.Memory == "" && metricsType == autoscalingv2.UtilizationMetricType), nil
}
// handleHPA handles the creation and management of a single HPA object.
func (o *AutoscaleOptions) handleHPA(hpa runtime.Object) error {
if err := o.Recorder.Record(hpa); err != nil {
return fmt.Errorf("error recording current command: %w", err)
}
if o.dryRunStrategy == cmdutil.DryRunClient {
printer, err := o.ToPrinter("created")
if err != nil {
return err
}
return printer.PrintObj(hpa, o.Out)
}
if err := util.CreateOrUpdateAnnotation(o.createAnnotation, hpa, scheme.DefaultJSONEncoder()); err != nil {
return err
}
createOptions := metav1.CreateOptions{}
if o.fieldManager != "" {
createOptions.FieldManager = o.fieldManager
}
if o.dryRunStrategy == cmdutil.DryRunServer {
createOptions.DryRun = []string{metav1.DryRunAll}
}
var actualHPA runtime.Object
var err error
switch typedHPA := hpa.(type) {
case *autoscalingv2.HorizontalPodAutoscaler:
actualHPA, err = o.HPAClientV2.HorizontalPodAutoscalers(o.namespace).Create(context.TODO(), typedHPA, createOptions)
case *autoscalingv1.HorizontalPodAutoscaler:
actualHPA, err = o.HPAClientV1.HorizontalPodAutoscalers(o.namespace).Create(context.TODO(), typedHPA, createOptions)
default:
return fmt.Errorf("unsupported HorizontalPodAutoscaler type %T", hpa)
}
if err != nil {
return err
}
printer, err := o.ToPrinter("autoscaled")
if err != nil {
return err
}
return printer.PrintObj(actualHPA, o.Out)
}
func (o *AutoscaleOptions) createHorizontalPodAutoscalerV2(refName string, mapping *meta.RESTMapping) (*autoscalingv2.HorizontalPodAutoscaler, error) {
name := o.Name
if len(name) == 0 {
name = refName
}
scaler := autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: mapping.GroupVersionKind.GroupVersion().String(),
Kind: mapping.GroupVersionKind.Kind,
Name: refName,
},
MaxReplicas: o.Max,
},
}
if o.Min > 0 {
scaler.Spec.MinReplicas = &o.Min
}
metrics := []autoscalingv2.MetricSpec{}
// add CPU metric if any of the CPU targets are specified
if o.CPUPercent > 0 {
cpuMetric := autoscalingv2.MetricSpec{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{},
},
}
cpuMetric.Resource.Target.Type = autoscalingv2.UtilizationMetricType
cpuMetric.Resource.Target.AverageUtilization = &o.CPUPercent
metrics = append(metrics, cpuMetric)
}
// add Cpu metric if any of the cpu targets are specified
if o.CPU != "" {
cpuMetric := autoscalingv2.MetricSpec{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{},
},
}
quantity, value, metricsType, err := parseResourceInput(o.CPU, corev1.ResourceCPU)
if err != nil {
return nil, err
}
switch metricsType {
case autoscalingv2.UtilizationMetricType:
cpuMetric.Resource.Target.Type = autoscalingv2.UtilizationMetricType
cpuMetric.Resource.Target.AverageUtilization = &value
case autoscalingv2.AverageValueMetricType:
cpuMetric.Resource.Target.Type = autoscalingv2.AverageValueMetricType
cpuMetric.Resource.Target.AverageValue = &quantity
default:
return nil, fmt.Errorf("unsupported metric type: %v", metricsType)
}
metrics = append(metrics, cpuMetric)
}
// add Memory metric if any of the memory targets are specified
if o.Memory != "" {
memoryMetric := autoscalingv2.MetricSpec{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{},
},
}
quantity, value, metricsType, err := parseResourceInput(o.Memory, corev1.ResourceMemory)
if err != nil {
return nil, err
}
switch metricsType {
case autoscalingv2.UtilizationMetricType:
memoryMetric.Resource.Target.Type = autoscalingv2.UtilizationMetricType
memoryMetric.Resource.Target.AverageUtilization = &value
case autoscalingv2.AverageValueMetricType:
memoryMetric.Resource.Target.Type = autoscalingv2.AverageValueMetricType
memoryMetric.Resource.Target.AverageValue = &quantity
default:
return nil, fmt.Errorf("unsupported metric type: %v", metricsType)
}
metrics = append(metrics, memoryMetric)
}
// Only set Metrics if there are any defined
if len(metrics) > 0 {
scaler.Spec.Metrics = metrics
} else {
scaler.Spec.Metrics = nil
}
return &scaler, nil
}
func (o *AutoscaleOptions) createHorizontalPodAutoscalerV1(refName string, mapping *meta.RESTMapping) *autoscalingv1.HorizontalPodAutoscaler {
func (o *AutoscaleOptions) createHorizontalPodAutoscaler(refName string, mapping *meta.RESTMapping) *autoscalingv1.HorizontalPodAutoscaler {
name := o.Name
if len(name) == 0 {
name = refName
@ -472,72 +291,3 @@ func (o *AutoscaleOptions) createHorizontalPodAutoscalerV1(refName string, mappi
return &scaler
}
// parseResourceInput parses a resource input string into either a utilization percentage or a quantity value.
// It supports:
// - Percentage values (e.g., "70%") for UtilizationMetricType
// - Quantity values with units (e.g., "500m", "2Gi")
// - Bare numbers without units, which are interpreted as:
// - CPU: milliCPU ("500" → "500m")
// - Memory: Mebibytes ("512" → "512Mi")
func parseResourceInput(input string, resourceType corev1.ResourceName) (apiresource.Quantity, int32, autoscalingv2.MetricTargetType, error) {
input = strings.TrimSpace(input)
if input == "" {
return apiresource.Quantity{}, 0, "", fmt.Errorf("empty input")
}
// Case 1: Handle percentage-based metrics like "70%"
percentValue, isPercent, err := parsePercentage(input)
if isPercent {
if err != nil {
return apiresource.Quantity{}, 0, "", err
}
return apiresource.Quantity{}, percentValue, autoscalingv2.UtilizationMetricType, nil
}
// Case 2: Try to interpret input as a bare number (e.g., "500"), and apply default float
valueFloat, err := strconv.ParseFloat(input, 64)
if err == nil {
unit, err := getDefaultUnitForResource(resourceType)
if err != nil {
return apiresource.Quantity{}, 0, "", err
}
inputWithUnit := fmt.Sprintf("%g%s", valueFloat, unit)
quantity, err := apiresource.ParseQuantity(inputWithUnit)
if err != nil {
return apiresource.Quantity{}, 0, "", err
}
return quantity, 0, autoscalingv2.AverageValueMetricType, nil
}
// Case 3: Parse normally if input has a valid unit (e.g., "500m", "2Gi")
quantity, err := apiresource.ParseQuantity(input)
if err != nil {
return apiresource.Quantity{}, 0, "", fmt.Errorf("invalid resource %s value: %s", resourceType, input)
}
return quantity, 0, autoscalingv2.AverageValueMetricType, nil
}
func getDefaultUnitForResource(resourceType corev1.ResourceName) (string, error) {
switch resourceType {
case corev1.ResourceCPU:
return "m", nil
case corev1.ResourceMemory:
return "Mi", nil
default:
return "", fmt.Errorf("unsupported resource type: %v", resourceType)
}
}
func parsePercentage(input string) (int32, bool, error) {
if !strings.HasSuffix(input, "%") {
return 0, false, nil
}
trimmed := strings.TrimSuffix(input, "%")
valueInt64, err := strconv.ParseInt(trimmed, 10, 32)
if err != nil || valueInt64 < 0 {
return 0, true, fmt.Errorf("invalid percentage value: %s", trimmed)
}
return int32(valueInt64), true, nil
}

View File

@ -23,10 +23,7 @@ import (
"github.com/stretchr/testify/assert"
autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
apiresource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/utils/ptr"
@ -80,131 +77,24 @@ func TestAutoscaleValidate(t *testing.T) {
},
expectedError: nil,
},
{
name: "CPUPercent appears with CPU",
options: &AutoscaleOptions{
Max: 5,
Min: 0,
CPU: "800",
CPUPercent: 20,
},
expectedError: fmt.Errorf("--cpu-percent and --cpu are mutually exclusive"),
},
{
name: "CPUPercent default (-1) with CPU",
options: &AutoscaleOptions{
Max: 5,
Min: 0,
CPU: "800",
CPUPercent: -1,
},
expectedError: nil,
},
{
name: "valid CPU percentage",
options: &AutoscaleOptions{
Max: 5,
CPU: "70%",
},
expectedError: nil,
},
{
name: "valid CPU numeric without unit",
options: &AutoscaleOptions{
Max: 5,
CPU: "500",
},
expectedError: nil,
},
{
name: "valid CPU with unit",
options: &AutoscaleOptions{
Max: 5,
CPU: "500m",
},
expectedError: nil,
},
{
name: "invalid CPU value (non-numeric)",
options: &AutoscaleOptions{
Max: 5,
CPU: "abc",
},
expectedError: fmt.Errorf("invalid resource cpu value: abc"),
},
{
name: "invalid CPU value (malformed unit)",
options: &AutoscaleOptions{
Max: 5,
CPU: "500xyz",
},
expectedError: fmt.Errorf("invalid resource cpu value: 500xyz"),
},
{
name: "valid memory percentage",
options: &AutoscaleOptions{
Max: 5,
Memory: "60%",
},
expectedError: nil,
},
{
name: "valid memory numeric without unit",
options: &AutoscaleOptions{
Max: 5,
Memory: "512",
},
expectedError: nil,
},
{
name: "valid memory with unit",
options: &AutoscaleOptions{
Max: 5,
Memory: "512Mi",
},
expectedError: nil,
},
{
name: "invalid memory value (non-numeric)",
options: &AutoscaleOptions{
Max: 5,
Memory: "xyz",
},
expectedError: fmt.Errorf("invalid resource memory value: xyz"),
},
{
name: "invalid memory value (MiB unit)",
options: &AutoscaleOptions{
Max: 5,
Memory: "512MiB",
},
expectedError: fmt.Errorf("invalid resource memory value: 512MiB"),
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
errorGot := tc.options.Validate()
if errorGot != nil {
assert.Equal(t, tc.expectedError.Error(), errorGot.Error())
}
assert.Equal(t, tc.expectedError, errorGot)
})
}
}
type createHorizontalPodAutoscalerTestCase struct {
name string
options *AutoscaleOptions
refName string
mapping *meta.RESTMapping
expectedHPAV2 *autoscalingv2.HorizontalPodAutoscaler
expectedHPAV1 *autoscalingv1.HorizontalPodAutoscaler
name string
options *AutoscaleOptions
refName string
mapping *meta.RESTMapping
expectedHPA *autoscalingv1.HorizontalPodAutoscaler
}
func TestCreateHorizontalPodAutoscalerV2(t *testing.T) {
cpu500m := apiresource.MustParse("500m")
mem512Mi := apiresource.MustParse("512Mi")
cpu2000m := apiresource.MustParse("2000m")
mem3Gi := apiresource.MustParse("3Gi")
func TestCreateHorizontalPodAutoscaler(t *testing.T) {
tests := []createHorizontalPodAutoscalerTestCase{
{
name: "create with all options",
@ -222,665 +112,7 @@ func TestCreateHorizontalPodAutoscalerV2(t *testing.T) {
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(80)),
},
},
},
},
},
},
},
{
name: "create without min replicas",
options: &AutoscaleOptions{
Name: "custom-name-2",
Max: 10,
Min: -1,
CPUPercent: 80,
},
refName: "deployment-2",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-2",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-2",
},
MinReplicas: nil,
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(80)),
},
},
},
},
},
},
},
{
name: "create without max replicas",
options: &AutoscaleOptions{
Name: "custom-name-3",
Max: -1,
Min: 2,
CPUPercent: 80,
},
refName: "deployment-3",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-3",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-3",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(-1),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(80)),
},
},
},
},
},
},
},
{
name: "create without cpu utilization",
options: &AutoscaleOptions{
Name: "custom-name-4",
Max: 10,
Min: 2,
CPUPercent: -1,
},
refName: "deployment-4",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-4",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-4",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
},
},
},
{
name: "create with replicaset reference",
options: &AutoscaleOptions{
Name: "replicaset-hpa",
Max: 5,
Min: 1,
CPUPercent: 70,
},
refName: "frontend",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "ReplicaSet",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "replicaset-hpa",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "ReplicaSet",
Name: "frontend",
},
MinReplicas: ptr.To(int32(1)),
MaxReplicas: int32(5),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(70)),
},
},
},
},
},
},
},
{
name: "create with statefulset reference",
options: &AutoscaleOptions{
Name: "statefulset-hpa",
Max: 8,
Min: 2,
CPUPercent: 60,
},
refName: "web",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "StatefulSet",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "statefulset-hpa",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: "web",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(8),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(60)),
},
},
},
},
},
},
},
{
name: "create with memory(use %) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
Memory: "50%",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(50)),
},
},
},
},
},
},
},
{
name: "create with both cpu(use %) and memory(use %) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
CPU: "70%",
Memory: "50%",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(70)),
},
},
},
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(50)),
},
},
},
},
},
},
},
{
name: "create with both cpu(use m unit) and memory(use %) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
CPU: "500m",
Memory: "50%",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &cpu500m,
},
},
},
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(50)),
},
},
},
},
},
},
},
{
name: "create with both cpu(no use unit) and memory(use %) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
CPU: "500",
Memory: "50%",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &cpu500m,
},
},
},
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: ptr.To(int32(50)),
},
},
},
},
},
},
},
{
name: "create with memory(no use unit) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
Memory: "512",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &mem512Mi,
},
},
},
},
},
},
},
{
name: "create with cpu(no use unit) and memory(no use unit) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
CPU: "500",
Memory: "512",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &cpu500m,
},
},
},
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &mem512Mi,
},
},
},
},
},
},
},
{
name: "create with both cpu(use m unit) and memory(use Gi unit) options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
CPU: "2000m",
Memory: "3Gi",
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV2: &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
Metrics: []autoscalingv2.MetricSpec{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricSpec
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &cpu2000m,
},
},
},
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#ResourceMetricSource
Name: corev1.ResourceMemory,
Target: autoscalingv2.MetricTarget{
// Reference: https://pkg.go.dev/k8s.io/api/autoscaling/v2#MetricTarget
Type: autoscalingv2.AverageValueMetricType,
AverageValue: &mem3Gi,
},
},
},
},
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
hpa, _ := tc.options.createHorizontalPodAutoscalerV2(tc.refName, tc.mapping)
assert.Equal(t, tc.expectedHPAV2, hpa)
})
}
}
func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
tests := []createHorizontalPodAutoscalerTestCase{
{
name: "create with all options",
options: &AutoscaleOptions{
Name: "custom-name",
Max: 10,
Min: 2,
CPUPercent: 80,
},
refName: "deployment-1",
mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
expectedHPA: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
@ -912,7 +144,7 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
Kind: "Deployment",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
expectedHPA: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-2",
},
@ -944,7 +176,7 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
Kind: "Deployment",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
expectedHPA: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-3",
},
@ -976,7 +208,7 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
Kind: "Deployment",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
expectedHPA: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-4",
},
@ -986,8 +218,9 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
Kind: "Deployment",
Name: "deployment-4",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
TargetCPUUtilizationPercentage: nil,
},
},
},
@ -1007,7 +240,7 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
Kind: "ReplicaSet",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
expectedHPA: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "replicaset-hpa",
},
@ -1039,7 +272,7 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
Kind: "StatefulSet",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
expectedHPA: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "statefulset-hpa",
},
@ -1058,8 +291,8 @@ func TestCreateHorizontalPodAutoscalerV1(t *testing.T) {
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
hpa := tc.options.createHorizontalPodAutoscalerV1(tc.refName, tc.mapping)
assert.Equal(t, tc.expectedHPAV1, hpa)
hpa := tc.options.createHorizontalPodAutoscaler(tc.refName, tc.mapping)
assert.Equal(t, tc.expectedHPA, hpa)
})
}
}

View File

@ -73,7 +73,6 @@ import (
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/version"
"k8s.io/kubectl/pkg/cmd/wait"
"k8s.io/kubectl/pkg/kuberc"
utilcomp "k8s.io/kubectl/pkg/util/completion"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
@ -83,6 +82,8 @@ import (
"k8s.io/kubectl/pkg/cmd/kustomize"
)
const kubectlCmdHeaders = "KUBECTL_COMMAND_HEADERS"
type KubectlOptions struct {
PluginHandler PluginHandler
Arguments []string
@ -141,23 +142,25 @@ func NewDefaultKubectlCommandWithArgs(o KubectlOptions) *cobra.Command {
}
}
} else if err == nil {
// Command exists(e.g. kubectl create), but it is not certain that
// subcommand also exists (e.g. kubectl create networkpolicy)
// we also have to eliminate kubectl create -f
if IsSubcommandPluginAllowed(foundCmd.Name()) && len(foundArgs) >= 1 && !strings.HasPrefix(foundArgs[0], "-") {
subcommand := foundArgs[0]
builtinSubcmdExist := false
for _, subcmd := range foundCmd.Commands() {
if subcmd.Name() == subcommand {
builtinSubcmdExist = true
break
if !cmdutil.CmdPluginAsSubcommand.IsDisabled() {
// Command exists(e.g. kubectl create), but it is not certain that
// subcommand also exists (e.g. kubectl create networkpolicy)
// we also have to eliminate kubectl create -f
if IsSubcommandPluginAllowed(foundCmd.Name()) && len(foundArgs) >= 1 && !strings.HasPrefix(foundArgs[0], "-") {
subcommand := foundArgs[0]
builtinSubcmdExist := false
for _, subcmd := range foundCmd.Commands() {
if subcmd.Name() == subcommand {
builtinSubcmdExist = true
break
}
}
}
if !builtinSubcmdExist {
if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, len(cmdPathPieces)-len(foundArgs)+1); err != nil {
fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err)
os.Exit(1)
if !builtinSubcmdExist {
if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, len(cmdPathPieces)-len(foundArgs)+1); err != nil {
fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err)
os.Exit(1)
}
}
}
}
@ -358,11 +361,6 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
flags.BoolVar(&warningsAsErrors, "warnings-as-errors", warningsAsErrors, "Treat warnings received from the server as errors and exit with a non-zero exit code")
pref := kuberc.NewPreferences()
if !cmdutil.KubeRC.IsDisabled() {
pref.AddFlags(flags)
}
kubeConfigFlags := o.ConfigFlags
if kubeConfigFlags == nil {
kubeConfigFlags = defaultConfigFlags().WithWarningPrinter(o.IOStreams)
@ -385,8 +383,6 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
// Avoid import cycle by setting ValidArgsFunction here instead of in NewCmdGet()
getCmd := get.NewCmdGet("kubectl", f, o.IOStreams)
getCmd.ValidArgsFunction = utilcomp.ResourceTypeAndNameCompletionFunc(f)
debugCmd := debug.NewCmdDebug(f, o.IOStreams)
debugCmd.ValidArgsFunction = utilcomp.ResourceTypeAndNameCompletionFunc(f)
groups := templates.CommandGroups{
{
@ -438,7 +434,7 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
proxyCmd,
cp.NewCmdCp(f, o.IOStreams),
auth.NewCmdAuth(f, o.IOStreams),
debugCmd,
debug.NewCmdDebug(f, o.IOStreams),
events.NewCmdEvents(f, o.IOStreams),
},
},
@ -494,15 +490,6 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
// Stop warning about normalization of flags. That makes it possible to
// add the klog flags later.
cmds.SetGlobalNormalizationFunc(cliflag.WordSepNormalizeFunc)
if !cmdutil.KubeRC.IsDisabled() {
_, err := pref.Apply(cmds, o.Arguments, o.IOStreams.ErrOut)
if err != nil {
fmt.Fprintf(o.IOStreams.ErrOut, "error occurred while applying preferences %v\n", err)
os.Exit(1)
}
}
return cmds
}
@ -520,9 +507,12 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
//
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/859-kubectl-headers
func addCmdHeaderHooks(cmds *cobra.Command, kubeConfigFlags *genericclioptions.ConfigFlags) {
if cmdutil.CmdHeaders.IsDisabled() {
klog.V(5).Infoln("kubectl command headers turned off")
return
// If the feature gate env var is set to "false", then do no add kubectl command headers.
if value, exists := os.LookupEnv(kubectlCmdHeaders); exists {
if value == "false" || value == "0" {
klog.V(5).Infoln("kubectl command headers turned off")
return
}
}
klog.V(5).Infoln("kubectl command headers turned on")
crt := &genericclioptions.CommandHeaderRoundTripper{}
@ -576,29 +566,3 @@ func registerCompletionFuncForGlobalFlags(cmd *cobra.Command, f cmdutil.Factory)
return utilcomp.ListUsersInConfig(toComplete), cobra.ShellCompDirectiveNoFileComp
}))
}
// GetLogVerbosity parses the provided command-line arguments to determine
// the verbosity level for logging. Returns string representing the verbosity
// level, or 0 if no verbosity flag is specified.
func GetLogVerbosity(args []string) string {
for i, arg := range args {
if arg == "--" {
// flags after "--" does not represent any flag of
// the command. We should short cut the iteration in here.
break
}
if arg == "--v" || arg == "-v" {
if i+1 < len(args) {
return args[i+1]
}
} else if strings.Contains(arg, "--v=") || strings.Contains(arg, "-v=") {
parg := strings.Split(arg, "=")
if len(parg) > 1 && parg[1] != "" {
return parg[1]
}
}
}
return "0"
}

View File

@ -29,7 +29,6 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/kubectl/pkg/cmd/plugin"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)
func TestNormalizationFuncGlobalExistence(t *testing.T) {
@ -382,6 +381,10 @@ func TestKubectlCommandHeadersHooks(t *testing.T) {
envVar: "false",
addsHooks: false,
},
"zero env var value; hooks NOT added": {
envVar: "0",
addsHooks: false,
},
}
for name, testCase := range tests {
@ -391,7 +394,7 @@ func TestKubectlCommandHeadersHooks(t *testing.T) {
if kubeConfigFlags.WrapConfigFn != nil {
t.Fatal("expected initial nil WrapConfigFn")
}
t.Setenv(string(cmdutil.CmdHeaders), testCase.envVar)
t.Setenv(kubectlCmdHeaders, testCase.envVar)
addCmdHeaderHooks(cmds, kubeConfigFlags)
// Valdidate whether the hooks were added.
if testCase.addsHooks && kubeConfigFlags.WrapConfigFn == nil {

View File

@ -69,6 +69,7 @@ func Example_view() {
// name: federal-context
// current-context: federal-context
// kind: Config
// preferences: {}
// users:
// - name: red-user
// user:

View File

@ -89,7 +89,7 @@ func NewCmdConfigGetContexts(streams genericiooptions.IOStreams, configAccess cl
// Complete assigns GetContextsOptions from the args.
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
supportedOutputTypes := sets.New[string]("", "name")
supportedOutputTypes := sets.NewString("", "name")
if !supportedOutputTypes.Has(o.outputFormat) {
return fmt.Errorf("--output %v is not available in kubectl config get-contexts; resetting to default output format", o.outputFormat)
}

View File

@ -55,7 +55,7 @@ func newNavigationSteps(path string) (*navigationSteps, error) {
if err != nil {
return nil, err
}
nextPart := findNameStep(individualParts[currPartIndex:], sets.KeySet(mapValueOptions))
nextPart := findNameStep(individualParts[currPartIndex:], sets.StringKeySet(mapValueOptions))
steps = append(steps, navigationStep{nextPart, mapValueType})
currPartIndex += len(strings.Split(nextPart, "."))
@ -98,7 +98,7 @@ func (s *navigationSteps) moreStepsRemaining() bool {
// findNameStep takes the list of parts and a set of valid tags that can be used after the name. It then walks the list of parts
// until it find a valid "next" tag or until it reaches the end of the parts and then builds the name back up out of the individual parts
func findNameStep(parts []string, typeOptions sets.Set[string]) string {
func findNameStep(parts []string, typeOptions sets.String) string {
if len(parts) == 0 {
return ""
}
@ -136,7 +136,7 @@ func getPotentialTypeValues(typeValue reflect.Type) (map[string]reflect.Type, er
return ret, nil
}
func findKnownValue(parts []string, valueOptions sets.Set[string]) int {
func findKnownValue(parts []string, valueOptions sets.String) int {
for i := range parts {
if valueOptions.Has(parts[i]) {
return i

View File

@ -85,6 +85,7 @@ contexts:
name: my-cluster
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
@ -164,6 +165,7 @@ contexts:
name: my-cluster
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
@ -245,6 +247,7 @@ contexts:
name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
@ -269,6 +272,7 @@ contexts:
name: my-cluster
current-context: my-cluster
kind: Config
preferences: {}
users:
- name: mu-cluster
user:

View File

@ -280,7 +280,7 @@ func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
Executor: &exec.DefaultRemoteExecutor{},
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
done := make(chan error)

View File

@ -116,7 +116,7 @@ var (
func AddSpecialVerb(verb string, gr schema.GroupResource) {
resources, ok := specialVerbs[verb]
if !ok {
resources = make([]schema.GroupResource, 0, 1)
resources = make([]schema.GroupResource, 1)
}
resources = append(resources, gr)
specialVerbs[verb] = resources
@ -425,7 +425,7 @@ func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resourc
// Create separate rule for each of the api group.
rules := []rbacv1.PolicyRule{}
for _, g := range sets.List(sets.KeySet(groupResourceMapping)) {
for _, g := range sets.StringKeySet(groupResourceMapping).List() {
rule := rbacv1.PolicyRule{}
rule.Verbs = verbs
rule.Resources = groupResourceMapping[g]

View File

@ -684,17 +684,14 @@ func TestAddSpecialVerb(t *testing.T) {
testCases := map[string]struct {
verb string
resource schema.GroupResource
isNew bool
}{
"existing verb": {
verb: "use",
resource: schema.GroupResource{Group: "my.custom.io", Resource: "one"},
isNew: false,
},
"new verb": {
verb: "new",
resource: schema.GroupResource{Group: "my.custom.io", Resource: "two"},
isNew: true,
},
}
@ -706,16 +703,6 @@ func TestAddSpecialVerb(t *testing.T) {
t.Errorf("missing expected verb: %s", tc.verb)
}
if tc.isNew {
if len(resources) != 1 {
t.Errorf("new verb should only contain one resource resources:%#v", resources)
}
if !reflect.DeepEqual(tc.resource, resources[0]) {
t.Errorf("miss expected resource:%#v", tc.resource)
}
return
}
for _, res := range resources {
if reflect.DeepEqual(tc.resource, res) {
return

View File

@ -98,10 +98,14 @@ var (
`)
)
var boundObjectKinds = map[string]string{
"Pod": "v1",
"Secret": "v1",
"Node": "v1",
func boundObjectKindToAPIVersions() map[string]string {
kinds := map[string]string{
"Pod": "v1",
"Secret": "v1",
"Node": "v1",
}
return kinds
}
func NewTokenOpts(ioStreams genericiooptions.IOStreams) *TokenOptions {
@ -145,7 +149,7 @@ func NewCmdCreateToken(f cmdutil.Factory, ioStreams genericiooptions.IOStreams)
cmd.Flags().DurationVar(&o.Duration, "duration", o.Duration, "Requested lifetime of the issued token. If not set or if set to 0, the lifetime will be determined by the server automatically. The server may return a token with a longer or shorter lifetime.")
cmd.Flags().StringVar(&o.BoundObjectKind, "bound-object-kind", o.BoundObjectKind, "Kind of an object to bind the token to. "+
"Supported kinds are "+strings.Join(sets.List(sets.KeySet(boundObjectKinds)), ", ")+". "+
"Supported kinds are "+strings.Join(sets.StringKeySet(boundObjectKindToAPIVersions()).List(), ", ")+". "+
"If set, --bound-object-name must be provided.")
cmd.Flags().StringVar(&o.BoundObjectName, "bound-object-name", o.BoundObjectName, "Name of an object to bind the token to. "+
"The token will expire when the object is deleted. "+
@ -222,8 +226,8 @@ func (o *TokenOptions) Validate() error {
return fmt.Errorf("--bound-object-uid can only be set if --bound-object-kind is provided")
}
} else {
if _, ok := boundObjectKinds[o.BoundObjectKind]; !ok {
return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.List(sets.KeySet(boundObjectKinds)), ", "))
if _, ok := boundObjectKindToAPIVersions()[o.BoundObjectKind]; !ok {
return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.StringKeySet(boundObjectKindToAPIVersions()).List(), ", "))
}
if len(o.BoundObjectName) == 0 {
return fmt.Errorf("--bound-object-name is required if --bound-object-kind is provided")
@ -246,7 +250,7 @@ func (o *TokenOptions) Run() error {
if len(o.BoundObjectKind) > 0 {
request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{
Kind: o.BoundObjectKind,
APIVersion: boundObjectKinds[o.BoundObjectKind],
APIVersion: boundObjectKindToAPIVersions()[o.BoundObjectKind],
Name: o.BoundObjectName,
UID: types.UID(o.BoundObjectUID),
}

View File

@ -99,7 +99,8 @@ func TestCreateToken(t *testing.T) {
serverResponseToken: "abc",
expectStdout: `apiVersion: authentication.k8s.io/v1
kind: TokenRequest
metadata: {}
metadata:
creationTimestamp: null
spec:
audiences: null
boundObjectRef: null

View File

@ -75,9 +75,6 @@ var (
debugging utilities without restarting the pod.
* Node: Create a new pod that runs in the node's host namespaces and can access
the node's filesystem.
Note: When a non-root user is configured for the entire target Pod, some capabilities granted
by debug profile may not work.
`))
debugExample = templates.Examples(i18n.T(`
@ -498,8 +495,6 @@ func (o *DebugOptions) debugByEphemeralContainer(ctx context.Context, pod *corev
}
klog.V(2).Infof("new ephemeral container: %#v", debugContainer)
o.displayWarning((*corev1.Container)(&debugContainer.EphemeralContainerCommon), pod)
debugJS, err := json.Marshal(debugPod)
if err != nil {
return nil, "", fmt.Errorf("error creating JSON for debug container: %v", err)
@ -616,16 +611,6 @@ func (o *DebugOptions) debugByCopy(ctx context.Context, pod *corev1.Pod) (*corev
if err != nil {
return nil, "", err
}
var debugContainer *corev1.Container
for i := range copied.Spec.Containers {
if copied.Spec.Containers[i].Name == dc {
debugContainer = &copied.Spec.Containers[i]
break
}
}
o.displayWarning(debugContainer, copied)
created, err := o.podClient.Pods(copied.Namespace).Create(ctx, copied, metav1.CreateOptions{})
if err != nil {
return nil, "", err
@ -639,32 +624,6 @@ func (o *DebugOptions) debugByCopy(ctx context.Context, pod *corev1.Pod) (*corev
return created, dc, nil
}
// Display warning message if some capabilities are set by profile and non-root user is specified in .Spec.SecurityContext.RunAsUser.(#1650)
func (o *DebugOptions) displayWarning(container *corev1.Container, pod *corev1.Pod) {
if container == nil {
return
}
if pod.Spec.SecurityContext.RunAsUser == nil || *pod.Spec.SecurityContext.RunAsUser == 0 {
return
}
if container.SecurityContext == nil {
return
}
if container.SecurityContext.RunAsUser != nil && *container.SecurityContext.RunAsUser == 0 {
return
}
if (container.SecurityContext.Privileged == nil || !*container.SecurityContext.Privileged) &&
(container.SecurityContext.Capabilities == nil || len(container.SecurityContext.Capabilities.Add) == 0) {
return
}
_, _ = fmt.Fprintln(o.ErrOut, `Warning: Non-root user is configured for the entire target Pod, and some capabilities granted by debug profile may not work. Please consider using "--custom" with a custom profile that specifies "securityContext.runAsUser: 0".`)
}
// generateDebugContainer returns a debugging pod and an EphemeralContainer suitable for use as a debug container
// in the given pod.
func (o *DebugOptions) generateDebugContainer(pod *corev1.Pod) (*corev1.Pod, *corev1.EphemeralContainer, error) {
@ -727,9 +686,6 @@ func (o *DebugOptions) generateNodeDebugPod(node *corev1.Node) (*corev1.Pod, err
p := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: pn,
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{

View File

@ -1468,9 +1468,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1525,9 +1522,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1584,9 +1578,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1640,9 +1631,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1695,9 +1683,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1738,9 +1723,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1789,9 +1771,6 @@ func TestGenerateNodeDebugPod(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1884,9 +1863,6 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1940,9 +1916,6 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "node-debugger-node-XXX-1",
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -1999,11 +1972,6 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
},
},
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
@ -2067,11 +2035,6 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
},
},
expected: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app.kubernetes.io/managed-by": "kubectl-debug",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{

View File

@ -506,10 +506,6 @@ func (o *DeleteOptions) PrintObj(info *resource.Info) {
operation = "force deleted"
}
if info.Namespaced() {
operation = fmt.Sprintf("%s from %s namespace", operation, info.Namespace)
}
switch o.DryRunStrategy {
case cmdutil.DryRunClient:
operation = fmt.Sprintf("%s (dry run)", operation)
@ -528,7 +524,7 @@ func (o *DeleteOptions) PrintObj(info *resource.Info) {
}
func (o *DeleteOptions) confirmation(infos []*resource.Info) bool {
fmt.Fprintf(o.Out, i18n.T("You are about to delete the following %d resource(s):\n"), len(infos)) //nolint:errcheck
fmt.Fprintf(o.Out, i18n.T("You are about to delete the following %d resource(s):\n"), len(infos))
for _, info := range infos {
groupKind := info.Mapping.GroupVersionKind
kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
@ -536,11 +532,11 @@ func (o *DeleteOptions) confirmation(infos []*resource.Info) bool {
kindString = strings.ToLower(groupKind.Kind)
}
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name) //nolint:errcheck
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)
}
fmt.Fprint(o.Out, i18n.T("Do you want to continue?")+" (y/N): ") //nolint:errcheck
fmt.Fprint(o.Out, i18n.T("Do you want to continue?")+" (y/n): ")
var input string
_, err := fmt.Fscanln(o.In, &input)
_, err := fmt.Fscan(o.In, &input)
if err != nil {
return false
}

View File

@ -375,7 +375,7 @@ func TestDeleteObjectWithInteractive(t *testing.T) {
}
cmd.Run(cmd, []string{})
if buf.String() != "You are about to delete the following 1 resource(s):\nreplicationcontroller/redis-master\nDo you want to continue? (y/N): replicationcontroller/redis-master\n" {
if buf.String() != "You are about to delete the following 1 resource(s):\nreplicationcontroller/redis-master\nDo you want to continue? (y/n): replicationcontroller/redis-master\n" {
t.Errorf("unexpected output: %s", buf.String())
}
@ -396,7 +396,7 @@ func TestDeleteObjectWithInteractive(t *testing.T) {
}
cmd.Run(cmd, []string{})
if buf.String() != "You are about to delete the following 1 resource(s):\nreplicationcontroller/redis-master\nDo you want to continue? (y/N): deletion is cancelled\n" {
if buf.String() != "You are about to delete the following 1 resource(s):\nreplicationcontroller/redis-master\nDo you want to continue? (y/n): deletion is cancelled\n" {
t.Errorf("unexpected output: %s", buf.String())
}
if buf.String() == ": replicationcontroller/redis-master\n" {
@ -972,39 +972,3 @@ func TestResourceErrors(t *testing.T) {
})
}
}
func TestDeleteMessageOutput(t *testing.T) {
cmdtesting.InitTestErrorHandler(t)
_, _, rc := cmdtesting.TestData()
tf := cmdtesting.NewTestFactory().WithNamespace("test-specific")
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test-specific/replicationcontrollers/redis-master" && m == "DELETE":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &rc.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdDelete(tf, streams)
err := cmd.Flags().Set("filename", "../../../testdata/redis-master-controller.yaml")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
cmd.Run(cmd, []string{})
if buf.String() != "replicationcontroller \"redis-master\" deleted from test-specific namespace\n" {
t.Errorf("unexpected output: %s", buf.String())
}
}

View File

@ -193,7 +193,7 @@ func (o *DescribeOptions) Run() error {
allErrs = append(allErrs, err)
}
errs := sets.New[string]()
errs := sets.NewString()
first := true
for _, info := range infos {
mapping := info.ResourceMapping()

View File

@ -64,7 +64,6 @@ func TestDiffProgram(t *testing.T) {
externalDiffCommands := [3]string{"diff", "diff -ruN", "diff --report-identical-files"}
t.Setenv("LANG", "C")
t.Setenv("LANGUAGE", "en_US")
for i, c := range externalDiffCommands {
t.Setenv("KUBECTL_EXTERNAL_DIFF", c)

View File

@ -326,7 +326,7 @@ func (o *DrainCmdOptions) RunDrain() error {
return err
}
drainedNodes := sets.New[string]()
drainedNodes := sets.NewString()
var fatal []error
remainingNodes := []string{}

View File

@ -30,7 +30,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/spf13/cobra"
yaml "go.yaml.in/yaml/v2"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericiooptions"
@ -40,6 +39,7 @@ import (
"k8s.io/kubectl/pkg/cmd/create"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
yaml "sigs.k8s.io/yaml/goyaml.v2"
)
type EditTestCase struct {
@ -172,7 +172,7 @@ func TestEdit(t *testing.T) {
t.Setenv("KUBE_EDITOR", "testdata/test_editor.sh")
t.Setenv("KUBE_EDITOR_CALLBACK", server.URL+"/callback")
testcases := sets.New[string]()
testcases := sets.NewString()
filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
@ -194,7 +194,7 @@ func TestEdit(t *testing.T) {
t.Fatalf("Error locating edit testcases")
}
for _, testcaseName := range testcases.UnsortedList() {
for _, testcaseName := range testcases.List() {
t.Run(testcaseName, func(t *testing.T) {
i = 0
name = testcaseName

View File

@ -25,7 +25,7 @@ import (
"os"
"strings"
yaml "go.yaml.in/yaml/v2"
yaml "sigs.k8s.io/yaml/goyaml.v2"
)
type EditTestCase struct {

View File

@ -3,7 +3,7 @@
"kind": "Service",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"svc1\",\"labels\":{\"app\":\"svc1\"}},\"spec\":{\"ports\":[{\"name\":\"80\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"
"kubectl.kubernetes.io/last-applied-configuration": "{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"svc1\",\"creationTimestamp\":null,\"labels\":{\"app\":\"svc1\"}},\"spec\":{\"ports\":[{\"name\":\"80\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"
},
"creationTimestamp": "2017-02-27T19:40:53Z",
"labels": {

View File

@ -7,7 +7,7 @@ kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","creationTimestamp":null,"labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
creationTimestamp: "2017-02-27T19:40:53Z"
labels:
app: svc1

View File

@ -7,7 +7,7 @@ kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","creationTimestamp":null,"labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
creationTimestamp: "2017-02-27T19:40:53Z"
labels:
app: svc1

View File

@ -33,6 +33,7 @@
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app": "nginx"
}

View File

@ -29,6 +29,7 @@ spec:
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:

View File

@ -29,6 +29,7 @@ spec:
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:

View File

@ -33,6 +33,7 @@
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app": "nginx"
}

View File

@ -3,7 +3,7 @@
"kind": "Service",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"svc1\",\"labels\":{\"app\":\"svc1\"}},\"spec\":{\"ports\":[{\"name\":\"80\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"
"kubectl.kubernetes.io/last-applied-configuration": "{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"svc1\",\"creationTimestamp\":null,\"labels\":{\"app\":\"svc1\"}},\"spec\":{\"ports\":[{\"name\":\"80\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"
},
"creationTimestamp": "2017-02-27T19:40:53Z",
"labels": {

View File

@ -7,7 +7,7 @@ kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","creationTimestamp":null,"labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
creationTimestamp: "2017-02-27T19:40:53Z"
labels:
app: svc1

View File

@ -7,7 +7,7 @@ kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","creationTimestamp":null,"labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
creationTimestamp: "2017-02-27T19:40:53Z"
labels:
app: svc1

View File

@ -3,7 +3,7 @@
"kind": "Service",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"svc1\",\"labels\":{\"app\":\"svc1\"}},\"spec\":{\"ports\":[{\"name\":\"80\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"
"kubectl.kubernetes.io/last-applied-configuration": "{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"svc1\",\"creationTimestamp\":null,\"labels\":{\"app\":\"svc1\"}},\"spec\":{\"ports\":[{\"name\":\"80\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"
},
"creationTimestamp": "2017-02-27T19:40:53Z",
"labels": {

View File

@ -7,7 +7,7 @@ kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","creationTimestamp":null,"labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
creationTimestamp: "2017-02-27T19:40:53Z"
labels:
app: svc1

View File

@ -7,7 +7,7 @@ kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
{"kind":"Service","apiVersion":"v1","metadata":{"name":"svc1","creationTimestamp":null,"labels":{"app":"svc1"}},"spec":{"ports":[{"name":"80","protocol":"TCP","port":80,"targetPort":80}],"selector":{"app":"svc1"},"type":"ClusterIP"},"status":{"loadBalancer":{}}}
creationTimestamp: "2017-02-27T19:40:53Z"
labels:
app: svc1

View File

@ -188,7 +188,7 @@ func (flags *EventsFlags) ToOptions() (*EventsOptions, error) {
}
if len(o.FilterTypes) > 0 {
o.FilterTypes = sets.List(sets.New[string](o.FilterTypes...))
o.FilterTypes = sets.NewString(o.FilterTypes...).List()
}
var printer printers.ResourcePrinter

View File

@ -114,26 +114,18 @@ func NewCmdExec(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Co
// RemoteExecutor defines the interface accepted by the Exec command - provided for test stubbing
type RemoteExecutor interface {
// Execute supports executing remote command in a pod.
Execute(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error
// ExecuteWithContext, in contrast to Execute, supports stopping the remote command via context cancellation.
ExecuteWithContext(ctx context.Context, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error
}
// DefaultRemoteExecutor is the standard implementation of remote command execution
type DefaultRemoteExecutor struct{}
func (d *DefaultRemoteExecutor) Execute(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
return d.ExecuteWithContext(context.Background(), url, config, stdin, stdout, stderr, tty, terminalSizeQueue)
}
func (*DefaultRemoteExecutor) ExecuteWithContext(ctx context.Context, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
func (*DefaultRemoteExecutor) Execute(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
exec, err := createExecutor(url, config)
if err != nil {
return err
}
return exec.StreamWithContext(ctx, remotecommand.StreamOptions{
return exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,

View File

@ -18,7 +18,6 @@ package exec
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
@ -46,10 +45,6 @@ type fakeRemoteExecutor struct {
}
func (f *fakeRemoteExecutor) Execute(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
return f.ExecuteWithContext(context.Background(), url, config, stdin, stdout, stderr, tty, terminalSizeQueue)
}
func (f *fakeRemoteExecutor) ExecuteWithContext(ctx context.Context, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
f.url = url
return f.execErr
}

View File

@ -56,77 +56,44 @@ var (
# Get the documentation of a specific field of a resource
kubectl explain pods.spec.containers
# Get the documentation of resources in different format
kubectl explain deployment --output=plaintext-openapiv2`))
)
const (
plaintextTemplateName = "plaintext"
plaintextOpenAPIV2TemplateName = "plaintext-openapiv2"
)
// ExplainFlags directly reflect the information that CLI is gathering via flags.
// They will be converted to Options, which reflect the runtime requirements for
// the command.
type ExplainFlags struct {
APIVersion string
OutputFormat string
Recursive bool
type ExplainOptions struct {
genericiooptions.IOStreams
CmdParent string
APIVersion string
Recursive bool
args []string
Mapper meta.RESTMapper
openAPIGetter openapi.OpenAPIResourcesGetter
// Name of the template to use with the openapiv3 template renderer.
OutputFormat string
// Client capable of fetching openapi documents from the user's cluster
OpenAPIV3Client openapiclient.Client
}
// NewExplainFlags returns a default ExplainFlags
func NewExplainFlags(streams genericiooptions.IOStreams) *ExplainFlags {
return &ExplainFlags{
OutputFormat: plaintextTemplateName,
func NewExplainOptions(parent string, streams genericiooptions.IOStreams) *ExplainOptions {
return &ExplainOptions{
IOStreams: streams,
CmdParent: parent,
OutputFormat: plaintextTemplateName,
}
}
// AddFlags registers flags for a cli
func (flags *ExplainFlags) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&flags.Recursive, "recursive", flags.Recursive, "Print the fields of fields (Currently only 1 level deep)")
cmd.Flags().StringVar(&flags.APIVersion, "api-version", flags.APIVersion, "Get different explanations for particular API version (API group/version)")
cmd.Flags().StringVarP(&flags.OutputFormat, "output", "o", plaintextTemplateName, "Format in which to render the schema (plaintext, plaintext-openapiv2)")
}
// ToOptions converts from CLI inputs to runtime input
func (flags *ExplainFlags) ToOptions(f cmdutil.Factory, parent string, args []string) (*ExplainOptions, error) {
mapper, err := f.ToRESTMapper()
if err != nil {
return nil, err
}
// Only openapi v3 needs the discovery client.
openAPIV3Client, err := f.OpenAPIV3Client()
if err != nil {
return nil, err
}
o := &ExplainOptions{
IOStreams: flags.IOStreams,
Recursive: flags.Recursive,
APIVersion: flags.APIVersion,
OutputFormat: flags.OutputFormat,
CmdParent: parent,
args: args,
Mapper: mapper,
openAPIGetter: f,
OpenAPIV3Client: openAPIV3Client,
}
return o, nil
}
// NewCmdExplain returns a cobra command for swagger docs
func NewCmdExplain(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
flags := NewExplainFlags(streams)
o := NewExplainOptions(parent, streams)
cmd := &cobra.Command{
Use: "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [-o|--output=plaintext|plaintext-openapiv2]",
@ -135,34 +102,37 @@ func NewCmdExplain(parent string, f cmdutil.Factory, streams genericiooptions.IO
Long: explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: explainExamples,
Run: func(cmd *cobra.Command, args []string) {
o, err := flags.ToOptions(f, parent, args)
cmdutil.CheckErr(err)
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
}
cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "When true, print the name of all the fields recursively. Otherwise, print the available fields with their description.")
cmd.Flags().StringVar(&o.APIVersion, "api-version", o.APIVersion, "Use given api-version (group/version) of the resource.")
flags.AddFlags(cmd)
// Only enable --output as a valid flag if the feature is enabled
cmd.Flags().StringVarP(&o.OutputFormat, "output", "o", plaintextTemplateName, "Format in which to render the schema. Valid values are: (plaintext, plaintext-openapiv2).")
return cmd
}
type ExplainOptions struct {
genericiooptions.IOStreams
func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.Mapper, err = f.ToRESTMapper()
if err != nil {
return err
}
Recursive bool
APIVersion string
// Name of the template to use with the openapiv3 template renderer.
OutputFormat string
// Only openapi v3 needs the discovery client.
o.OpenAPIV3Client, err = f.OpenAPIV3Client()
if err != nil {
return err
}
CmdParent string
args []string
Mapper meta.RESTMapper
openAPIGetter openapi.OpenAPIResourcesGetter
// Client capable of fetching openapi documents from the user's cluster
OpenAPIV3Client openapiclient.Client
// Lazy-load the OpenAPI V2 Resources, so they're not loaded when using OpenAPI V3.
o.openAPIGetter = f
o.args = args
return nil
}
func (o *ExplainOptions) Validate() error {

View File

@ -57,9 +57,9 @@ func TestExplainInvalidArgs(t *testing.T) {
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
flags := explain.NewExplainFlags(genericiooptions.NewTestIOStreamsDiscard())
opts, err := flags.ToOptions(tf, "kubectl", []string{})
opts := explain.NewExplainOptions("kubectl", genericiooptions.NewTestIOStreamsDiscard())
cmd := explain.NewCmdExplain("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard())
err := opts.Complete(tf, cmd, []string{})
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@ -69,7 +69,7 @@ func TestExplainInvalidArgs(t *testing.T) {
t.Error("unexpected non-error")
}
opts, err = flags.ToOptions(tf, "kubectl", []string{"resource1", "resource2"})
err = opts.Complete(tf, cmd, []string{"resource1", "resource2"})
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@ -84,9 +84,9 @@ func TestExplainNotExistResource(t *testing.T) {
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
flags := explain.NewExplainFlags(genericiooptions.NewTestIOStreamsDiscard())
opts, err := flags.ToOptions(tf, "kubectl", []string{"foo"})
opts := explain.NewExplainOptions("kubectl", genericiooptions.NewTestIOStreamsDiscard())
cmd := explain.NewCmdExplain("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard())
err := opts.Complete(tf, cmd, []string{"foo"})
if err != nil {
t.Fatalf("unexpected error %v", err)
}

View File

@ -694,6 +694,7 @@ func TestExposeOverride(t *testing.T) {
expected: `apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
svc: test
name: foo
@ -716,6 +717,7 @@ status:
expected: `apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
svc: test
name: foo
@ -743,6 +745,7 @@ status:
expected: `apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
svc: test
name: foo
@ -770,6 +773,7 @@ status:
expected: `apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
svc: test
name: foo

View File

@ -182,7 +182,7 @@ func NewCmdGet(parent string, f cmdutil.Factory, streams genericiooptions.IOStre
cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes.")
cmd.Flags().BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.")
cmd.Flags().BoolVar(&o.OutputWatchEvents, "output-watch-events", o.OutputWatchEvents, "Output watch event objects when --watch or --watch-only is used. Existing objects are output as initial ADDED events.")
cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If set to true, suppresses NotFound error for specific objects that do not exist. Using this flag with commands that query for collections of resources has no effect when no resources are found.")
cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")
cmd.Flags().StringVar(&o.FieldSelector, "field-selector", o.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
addServerPrintColumnFlags(cmd, o)
@ -486,7 +486,7 @@ func (o *GetOptions) Run(f cmdutil.Factory, args []string) error {
}
allErrs := []error{}
errs := sets.New[string]()
errs := sets.NewString()
infos, err := r.Infos()
if err != nil {
allErrs = append(allErrs, err)
@ -623,10 +623,6 @@ func (o *GetOptions) watch(f cmdutil.Factory, args []string) error {
}
infos, err := r.Infos()
if err != nil {
// Ignore "NotFound" error when ignore-not-found is set to true
if apierrors.IsNotFound(err) && o.IgnoreNotFound {
return nil
}
return err
}
if multipleGVKsRequested(infos) {

View File

@ -21,7 +21,6 @@ import (
"encoding/json"
"fmt"
"io"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"net/http"
"reflect"
"strings"
@ -712,7 +711,7 @@ func TestGetEmptyTable(t *testing.T) {
}
}
func TestGetNonExistObject(t *testing.T) {
func TestGetObjectIgnoreNotFound(t *testing.T) {
cmdtesting.InitTestErrorHandler(t)
ns := &corev1.NamespaceList{
@ -746,63 +745,6 @@ func TestGetNonExistObject(t *testing.T) {
}),
}
cmdutil.BehaviorOnFatal(func(str string, code int) {
expectedErr := "Error from server (NotFound): the server could not find the requested resource (get pods nonexistentpod)"
if str != expectedErr {
t.Errorf("unexpected error: %s\nexpected: %s", str, expectedErr)
}
})
// Get nonexistentpod fails with above error message
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdGet("kubectl", tf, streams)
cmd.SetOut(buf)
cmd.SetErr(buf)
cmd.Run(cmd, []string{"pods", "nonexistentpod"})
}
func TestGetNonExistObjectIgnoreNotFound(t *testing.T) {
cmdtesting.InitTestErrorHandler(t)
ns := &corev1.NamespaceList{
ListMeta: metav1.ListMeta{
ResourceVersion: "1",
},
Items: []corev1.Namespace{
{
ObjectMeta: metav1.ObjectMeta{Name: "testns", Namespace: "test", ResourceVersion: "11"},
Spec: corev1.NamespaceSpec{},
},
},
}
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/pods/nonexistentpod" && m == "GET":
return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.StringBody("")}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &ns.Items[0])}, nil
default:
t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
return nil, nil
}
}),
}
cmdutil.BehaviorOnFatal(func(str string, code int) {
expectedErr := ""
if str != expectedErr {
t.Errorf("unexpected error: %s\nexpected: %s", str, expectedErr)
}
})
// Get nonexistentpod passes without error when setting ignore-not-found to true
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdGet("kubectl", tf, streams)
cmd.SetOut(buf)
@ -1496,6 +1438,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"creationTimestamp": null,
"name": "foo",
"namespace": "test",
"resourceVersion": "10"
@ -1514,6 +1457,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"creationTimestamp": null,
"name": "bar",
"namespace": "test",
"resourceVersion": "11"
@ -1532,6 +1476,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"creationTimestamp": null,
"name": "baz",
"namespace": "test",
"resourceVersion": "12"
@ -2184,93 +2129,6 @@ foo <unknown>
}
}
func TestWatchNonExistObject(t *testing.T) {
pods, _ := watchTestData()
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/pods/nonexistentpod" && m == "GET":
return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.StringBody("")}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
default:
t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
return nil, nil
}
}),
}
cmdutil.BehaviorOnFatal(func(str string, code int) {
expectedErr := "Error from server (NotFound): the server could not find the requested resource (get pods nonexistentpod)"
if str != expectedErr {
t.Errorf("unexpected error: %s\nexpected: %s", str, expectedErr)
}
})
// Get nonexistentpod fails with above error message
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdGet("kubectl", tf, streams)
cmd.SetOut(buf)
cmd.SetErr(buf)
cmd.Flags().Set("watch", "true") //nolint:errcheck
cmd.Flags().Set("output", "yaml") //nolint:errcheck
cmd.Run(cmd, []string{"pods", "nonexistentpod"})
if buf.String() != "" {
t.Errorf("unexpected output: %s", buf.String())
}
}
func TestWatchNonExistObjectIgnoreNotFound(t *testing.T) {
pods, _ := watchTestData()
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/pods/nonexistentpod" && m == "GET":
return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.StringBody("")}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
default:
t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
return nil, nil
}
}),
}
cmdutil.BehaviorOnFatal(func(str string, code int) {
expectedErr := ""
if str != expectedErr {
t.Errorf("unexpected error: %s\nexpected: %s", str, expectedErr)
}
})
// Get nonexistentpod passes without error when setting ignore-not-found to true
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdGet("kubectl", tf, streams)
cmd.SetOut(buf)
cmd.SetErr(buf)
cmd.Flags().Set("ignore-not-found", "true") //nolint:errcheck
cmd.Flags().Set("watch", "true") //nolint:errcheck
cmd.Flags().Set("output", "yaml") //nolint:errcheck
cmd.Run(cmd, []string{"pods", "nonexistentpod"})
if buf.String() != "" {
t.Errorf("unexpected output: %s", buf.String())
}
}
func TestWatchStatus(t *testing.T) {
pods, events := watchTestData()
events = append(events, watch.Event{Type: "ERROR", Object: &metav1.Status{Status: "Failure", Reason: "InternalServerError", Message: "Something happened"}})
@ -2509,10 +2367,10 @@ DELETED test pod/foo 0/0 0 <unknown> <none>
},
{
format: "json",
expected: `{"type":"ADDED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"name":"bar","namespace":"test","resourceVersion":"9"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
{"type":"ADDED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"name":"foo","namespace":"test","resourceVersion":"10"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
{"type":"MODIFIED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"name":"foo","namespace":"test","resourceVersion":"11"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
{"type":"DELETED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"name":"foo","namespace":"test","resourceVersion":"12"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
expected: `{"type":"ADDED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"bar","namespace":"test","resourceVersion":"9"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
{"type":"ADDED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"foo","namespace":"test","resourceVersion":"10"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
{"type":"MODIFIED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"foo","namespace":"test","resourceVersion":"11"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
{"type":"DELETED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"foo","namespace":"test","resourceVersion":"12"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
`,
},
{
@ -2521,6 +2379,7 @@ DELETED test pod/foo 0/0 0 <unknown> <none>
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: bar
namespace: test
resourceVersion: "9"
@ -2538,6 +2397,7 @@ object:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: foo
namespace: test
resourceVersion: "10"
@ -2555,6 +2415,7 @@ object:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: foo
namespace: test
resourceVersion: "11"
@ -2572,6 +2433,7 @@ object:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: foo
namespace: test
resourceVersion: "12"

View File

@ -22,6 +22,7 @@ import (
"reflect"
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra"
jsonpatch "gopkg.in/evanphx/json-patch.v4"
"k8s.io/klog/v2"
@ -136,7 +137,7 @@ func NewCmdPatch(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra
cmd.Flags().StringVarP(&o.Patch, "patch", "p", "", "The patch to be applied to the resource JSON file.")
cmd.Flags().StringVar(&o.PatchFile, "patch-file", "", "A file containing a patch to be applied to the resource.")
cmd.Flags().StringVar(&o.PatchType, "type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.List(sets.KeySet(patchTypes))))
cmd.Flags().StringVar(&o.PatchType, "type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, patch will operate on the content of the file, not the server-side resource.")
@ -193,7 +194,7 @@ func (o *PatchOptions) Validate() error {
}
if len(o.PatchType) != 0 {
if _, ok := patchTypes[strings.ToLower(o.PatchType)]; !ok {
return fmt.Errorf("--type must be one of %v, not %q", sets.List(sets.KeySet(patchTypes)), o.PatchType)
return fmt.Errorf("--type must be one of %v, not %q", sets.StringKeySet(patchTypes).List(), o.PatchType)
}
}
return nil
@ -259,7 +260,7 @@ func (o *PatchOptions) RunPatch() error {
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes, nil)
if err != nil {
if apierrors.IsUnsupportedMediaType(err) {
return fmt.Errorf("%s is not supported by %s: %w", patchType, mapping.GroupVersionKind, err)
return errors.Wrap(err, fmt.Sprintf("%s is not supported by %s", patchType, mapping.GroupVersionKind))
}
return err
}

View File

@ -247,7 +247,7 @@ func convertPodNamedPortToNumber(ports []string, pod corev1.Pod) ([]string, erro
return converted, nil
}
func checkUDPPorts(udpOnlyPorts sets.Set[int], ports []string, obj metav1.Object) error {
func checkUDPPorts(udpOnlyPorts sets.Int, ports []string, obj metav1.Object) error {
for _, port := range ports {
_, remotePort := splitPort(port)
portNum, err := strconv.Atoi(remotePort)
@ -281,8 +281,8 @@ func checkUDPPorts(udpOnlyPorts sets.Set[int], ports []string, obj metav1.Object
// checkUDPPortInService returns an error if remote port in Service is a UDP port
// TODO: remove this check after #47862 is solved
func checkUDPPortInService(ports []string, svc *corev1.Service) error {
udpPorts := sets.New[int]()
tcpPorts := sets.New[int]()
udpPorts := sets.NewInt()
tcpPorts := sets.NewInt()
for _, port := range svc.Spec.Ports {
portNum := int(port.Port)
switch port.Protocol {
@ -298,8 +298,8 @@ func checkUDPPortInService(ports []string, svc *corev1.Service) error {
// checkUDPPortInPod returns an error if remote port in Pod is a UDP port
// TODO: remove this check after #47862 is solved
func checkUDPPortInPod(ports []string, pod *corev1.Pod) error {
udpPorts := sets.New[int]()
tcpPorts := sets.New[int]()
udpPorts := sets.NewInt()
tcpPorts := sets.NewInt()
for _, ct := range pod.Spec.Containers {
for _, ctPort := range ct.Ports {
portNum := int(ctPort.ContainerPort)

View File

@ -105,7 +105,7 @@ func NewCmdRolloutHistory(f cmdutil.Factory, streams genericiooptions.IOStreams)
return cmd
}
// Complete completes all the required options
// Complete completes al the required options
func (o *RolloutHistoryOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.Resources = args
@ -177,15 +177,7 @@ func (o *RolloutHistoryOptions) Run() error {
}
if o.Revision > 0 {
// Ensure the specified revision exists before printing
revision, exists := historyInfo[o.Revision]
if !exists {
return fmt.Errorf("unable to find the specified revision")
}
if err := printer.PrintObj(revision, o.Out); err != nil {
return err
}
printer.PrintObj(historyInfo[o.Revision], o.Out)
} else {
sortedKeys := make([]int64, 0, len(historyInfo))
for k := range historyInfo {

View File

@ -280,12 +280,15 @@ func TestRolloutHistoryWithOutput(t *testing.T) {
"kind": "ReplicaSet",
"apiVersion": "apps/v1",
"metadata": {
"name": "rev2"
"name": "rev2",
"creationTimestamp": null
},
"spec": {
"selector": null,
"template": {
"metadata": {},
"metadata": {
"creationTimestamp": null
},
"spec": {
"containers": null
}
@ -302,11 +305,13 @@ func TestRolloutHistoryWithOutput(t *testing.T) {
expectedOutput: `apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
name: rev2
spec:
selector: null
template:
metadata: {}
metadata:
creationTimestamp: null
spec:
containers: null
status:
@ -318,11 +323,13 @@ status:
expectedOutput: `apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
name: rev1
spec:
selector: null
template:
metadata: {}
metadata:
creationTimestamp: null
spec:
containers: null
status:
@ -331,11 +338,13 @@ status:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
name: rev2
spec:
selector: null
template:
metadata: {}
metadata:
creationTimestamp: null
spec:
containers: null
status:
@ -392,88 +401,6 @@ replicaset.apps/rev2
}
}
func TestRolloutHistoryErrors(t *testing.T) {
ns := scheme.Codecs.WithoutConversion()
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
encoder := ns.EncoderForVersion(info.Serializer, rolloutPauseGroupVersionEncoder)
tf.Client = &RolloutPauseRESTClient{
RESTClient: &fake.RESTClient{
GroupVersion: rolloutPauseGroupVersionEncoder,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/deployments/foo" && m == "GET":
responseDeployment := &appsv1.Deployment{}
responseDeployment.Name = "foo"
body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseDeployment))))
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
},
}
testCases := map[string]struct {
revision int64
outputFormat string
expectedError string
}{
"get non-existing revision as yaml": {
revision: 999,
outputFormat: "yaml",
expectedError: "unable to find the specified revision",
},
"get non-existing revision as json": {
revision: 999,
outputFormat: "json",
expectedError: "unable to find the specified revision",
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
fhv := setupFakeHistoryViewer(t)
fhv.getHistoryFn = func(namespace, name string) (map[int64]runtime.Object, error) {
return map[int64]runtime.Object{
1: &appsv1.ReplicaSet{ObjectMeta: v1.ObjectMeta{Name: "rev1"}},
2: &appsv1.ReplicaSet{ObjectMeta: v1.ObjectMeta{Name: "rev2"}},
}, nil
}
streams := genericiooptions.NewTestIOStreamsDiscard()
o := NewRolloutHistoryOptions(streams)
printFlags := &genericclioptions.PrintFlags{
JSONYamlPrintFlags: &genericclioptions.JSONYamlPrintFlags{
ShowManagedFields: true,
},
OutputFormat: &tc.outputFormat,
OutputFlagSpecified: func() bool {
return true
},
}
o.PrintFlags = printFlags
o.Revision = tc.revision
if err := o.Complete(tf, nil, []string{"deployment/foo"}); err != nil {
t.Fatalf("unexpected error: %v", err)
}
err := o.Run()
if err != nil && err.Error() != tc.expectedError {
t.Fatalf("expected '%s' error, but got: %v", tc.expectedError, err)
}
})
}
}
func TestValidate(t *testing.T) {
opts := RolloutHistoryOptions{
Revision: 0,

View File

@ -655,6 +655,7 @@ func TestRunOverride(t *testing.T) {
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: test
name: test
@ -677,6 +678,7 @@ status: {}
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: test
name: test
@ -699,6 +701,7 @@ status: {}
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: test
name: test
@ -726,6 +729,7 @@ status: {}
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
foo: bar
run: test

View File

@ -15,4 +15,4 @@ limitations under the License.
*/
// Package env provides functions to incorporate environment variables into set env.
package env
package env // import "k8s.io/kubectl/pkg/cmd/set/env"

View File

@ -61,7 +61,7 @@ func SplitEnvironmentFromResources(args []string) (resources, envArgs []string,
// envVarType is for making errors more specific to user intentions.
func parseIntoEnvVar(spec []string, defaultReader io.Reader, envVarType string) ([]v1.EnvVar, []string, bool, error) {
env := []v1.EnvVar{}
exists := sets.New[string]()
exists := sets.NewString()
var remove []string
usedStdin := false
for _, envSpec := range spec {

View File

@ -158,11 +158,11 @@ func splitMaybeSubscriptedPath(fieldPath string) (string, string, bool) {
// formatMap formats map[string]string to a string.
func formatMap(m map[string]string) (fmtStr string) {
// output with keys in sorted order to provide stable output
keys := sets.New[string]()
keys := sets.NewString()
for key := range m {
keys.Insert(key)
}
for _, key := range sets.List(keys) {
for _, key := range keys.List() {
fmtStr += fmt.Sprintf("%v=%q\n", key, m[key])
}
fmtStr = strings.TrimSuffix(fmtStr, "\n")

View File

@ -19,7 +19,7 @@ package set
import (
"strings"
v1 "k8s.io/api/core/v1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/strategicpatch"
@ -139,7 +139,7 @@ func findEnv(env []v1.EnvVar, name string) (v1.EnvVar, bool) {
// If a variable is both added and removed, the removal takes precedence.
func updateEnv(existing []v1.EnvVar, env []v1.EnvVar, remove []string) []v1.EnvVar {
out := []v1.EnvVar{}
covered := sets.New[string](remove...)
covered := sets.NewString(remove...)
for _, e := range existing {
if covered.Has(e.Name) {
continue

View File

@ -206,7 +206,7 @@ func (o *SubjectOptions) Validate() error {
func (o *SubjectOptions) Run(fn updateSubjects) error {
patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) {
subjects := []rbacv1.Subject{}
for _, user := range sets.List(sets.New[string](o.Users...)) {
for _, user := range sets.NewString(o.Users...).List() {
subject := rbacv1.Subject{
Kind: rbacv1.UserKind,
APIGroup: rbacv1.GroupName,
@ -214,7 +214,7 @@ func (o *SubjectOptions) Run(fn updateSubjects) error {
}
subjects = append(subjects, subject)
}
for _, group := range sets.List(sets.New[string](o.Groups...)) {
for _, group := range sets.NewString(o.Groups...).List() {
subject := rbacv1.Subject{
Kind: rbacv1.GroupKind,
APIGroup: rbacv1.GroupName,
@ -222,7 +222,7 @@ func (o *SubjectOptions) Run(fn updateSubjects) error {
}
subjects = append(subjects, subject)
}
for _, sa := range sets.List(sets.New[string](o.ServiceAccounts...)) {
for _, sa := range sets.NewString(o.ServiceAccounts...).List() {
tokens := strings.Split(sa, ":")
namespace := tokens[0]
name := tokens[1]

View File

@ -38,7 +38,7 @@ const (
// It also validates the spec. For example, the form `<key>` may be used to remove a taint, but not to add one.
func parseTaints(spec []string) ([]corev1.Taint, []corev1.Taint, error) {
var taints, taintsToRemove []corev1.Taint
uniqueTaints := map[corev1.TaintEffect]sets.Set[string]{}
uniqueTaints := map[corev1.TaintEffect]sets.String{}
for _, taintSpec := range spec {
if strings.HasSuffix(taintSpec, "-") {
@ -62,7 +62,7 @@ func parseTaints(spec []string) ([]corev1.Taint, []corev1.Taint, error) {
}
// add taint to existingTaints for uniqueness check
if len(uniqueTaints[newTaint.Effect]) == 0 {
uniqueTaints[newTaint.Effect] = sets.Set[string]{}
uniqueTaints[newTaint.Effect] = sets.String{}
}
uniqueTaints[newTaint.Effect].Insert(newTaint.Key)

View File

@ -39,31 +39,9 @@ var (
topLong = templates.LongDesc(i18n.T(`
Display resource (CPU/memory) usage.
This command provides a view of recent resource consumption for nodes and pods.
It fetches metrics from the Metrics Server, which aggregates this data from the
kubelet on each node. The Metrics Server must be installed and running in the
cluster for this command to work.
The top command allows you to see the resource consumption for nodes or pods.
The metrics shown are specifically optimized for Kubernetes autoscaling
decisions, such as those made by the Horizontal Pod Autoscaler (HPA) and
Vertical Pod Autoscaler (VPA). Because of this, the values may not match those
from standard OS tools like 'top', as the metrics are designed to provide a
stable signal for autoscalers rather than for pinpoint accuracy.
When to use this command:
* For on-the-fly spot-checks of resource usage (e.g. identify which pods
are consuming the most resources at a glance, or get a quick sense of the load
on your nodes)
* Understand current resource consumption patterns
* Validate the behavior of your HPA or VPA configurations by seeing the metrics
they use for scaling decisions.
It is not intended to be a replacement for full-featured monitoring solutions.
Its primary design goal is to provide a low-overhead signal for autoscalers,
not to be a perfectly accurate monitoring tool. For high-accuracy reporting,
historical analysis, dashboarding, or alerting, you should use a dedicated
monitoring solution.`))
This command requires Metrics Server to be correctly configured and working on the server. `))
)
func NewCmdTop(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {

View File

@ -19,9 +19,9 @@ package top
import (
"context"
"errors"
"github.com/spf13/cobra"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/cli-runtime/pkg/genericiooptions"
@ -45,7 +45,6 @@ type TopNodeOptions struct {
NoHeaders bool
UseProtocolBuffers bool
ShowCapacity bool
ShowSwap bool
NodeClient corev1client.CoreV1Interface
Printer *metricsutil.TopCmdPrinter
@ -96,7 +95,6 @@ func NewCmdTopNode(f cmdutil.Factory, o *TopNodeOptions, streams genericiooption
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If present, print output without headers")
cmd.Flags().BoolVar(&o.UseProtocolBuffers, "use-protocol-buffers", o.UseProtocolBuffers, "Enables using protocol-buffers to access Metrics API.")
cmd.Flags().BoolVar(&o.ShowCapacity, "show-capacity", o.ShowCapacity, "Print node resources based on Capacity instead of Allocatable(default) of the nodes.")
cmd.Flags().BoolVar(&o.ShowSwap, "show-swap", o.ShowSwap, "Print node resources related to swap memory.")
return cmd
}
@ -129,7 +127,7 @@ func (o *TopNodeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
o.NodeClient = clientset.CoreV1()
o.Printer = metricsutil.NewTopCmdPrinter(o.Out, o.ShowSwap)
o.Printer = metricsutil.NewTopCmdPrinter(o.Out)
return nil
}
@ -200,14 +198,6 @@ func (o TopNodeOptions) RunTopNode() error {
} else {
availableResources[n.Name] = n.Status.Capacity
}
if n.Status.NodeInfo.Swap != nil && n.Status.NodeInfo.Swap.Capacity != nil {
swapCapacity := *n.Status.NodeInfo.Swap.Capacity
availableResources[n.Name]["swap"] = *resource.NewQuantity(swapCapacity, resource.BinarySI)
} else {
o.Printer.RegisterMissingResource(n.Name, metricsutil.ResourceSwap)
}
}
return o.Printer.PrintNodeMetrics(metrics.Items, availableResources, o.NoHeaders, o.SortBy)

View File

@ -424,111 +424,3 @@ func TestTopNodeWithSortByMemoryMetricsFrom(t *testing.T) {
}
}
func TestTopNodeWithSwap(t *testing.T) {
runTopCmd := func(expectedMetrics *metricsv1beta1api.NodeMetricsList, nodes *v1.NodeList) (result string) {
cmdtesting.InitTestErrorHandler(t)
expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
ns := scheme.Codecs.WithoutConversion()
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/api":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: io.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
case p == "/apis":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: io.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
case p == expectedNodePath && m == "GET":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, nodes)}, nil
default:
t.Fatalf("unexpected request: %#v\nGot URL: %#v\n", req, req.URL)
return nil, nil
}
}),
}
fakemetricsClientset := &metricsfake.Clientset{}
fakemetricsClientset.AddReactor("list", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
return true, expectedMetrics, nil
})
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdTopNode(tf, nil, streams)
// TODO in the long run, we want to test most of our commands like this. Wire the options struct with specific mocks
// TODO then check the particular Run functionality and harvest results from fake clients
cmdOptions := &TopNodeOptions{
IOStreams: streams,
ShowSwap: true,
}
if err := cmdOptions.Complete(tf, cmd, []string{}); err != nil {
t.Fatal(err)
}
cmdOptions.MetricsClient = fakemetricsClientset
if err := cmdOptions.Validate(); err != nil {
t.Fatal(err)
}
if err := cmdOptions.RunTopNode(); err != nil {
t.Fatal(err)
}
return buf.String()
}
for _, tc := range []struct {
name string
isSwapDisabledOnNodes bool
}{
{
name: "nodes with swap",
isSwapDisabledOnNodes: false,
},
{
name: "nodes without swap",
isSwapDisabledOnNodes: true,
},
} {
t.Run(tc.name, func(t *testing.T) {
expectedMetrics, nodes := testNodeV1beta1MetricsData()
if tc.isSwapDisabledOnNodes {
for i := range expectedMetrics.Items {
delete(expectedMetrics.Items[i].Usage, "swap")
}
for i := range nodes.Items {
nodes.Items[i].Status.NodeInfo.Swap = nil
}
}
result := runTopCmd(expectedMetrics, nodes)
fmt.Printf("%s\n", result)
if !strings.Contains(result, "SWAP(bytes)") {
t.Errorf("missing SWAP(bytes) header: \n%s", result)
}
if !strings.Contains(result, "SWAP(%)") {
t.Errorf("missing SWAP(%%) header: \n%s", result)
}
if tc.isSwapDisabledOnNodes {
if !strings.Contains(result, "<unknown>") {
t.Errorf("expected swap to be <unknown>: \n%s", result)
}
}
for _, m := range expectedMetrics.Items {
if !strings.Contains(result, m.Name) {
t.Errorf("missing metrics for %s: \n%s", m.Name, result)
}
if _, foundSwapMetric := m.Usage["swap"]; foundSwapMetric != !tc.isSwapDisabledOnNodes {
t.Errorf("missing swap metric for %s: \n%s", m.Name, result)
}
}
})
}
}

View File

@ -53,7 +53,6 @@ type TopPodOptions struct {
NoHeaders bool
UseProtocolBuffers bool
Sum bool
ShowSwap bool
PodClient corev1client.PodsGetter
Printer *metricsutil.TopCmdPrinter
@ -118,7 +117,6 @@ func NewCmdTopPod(f cmdutil.Factory, o *TopPodOptions, streams genericiooptions.
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If present, print output without headers.")
cmd.Flags().BoolVar(&o.UseProtocolBuffers, "use-protocol-buffers", o.UseProtocolBuffers, "Enables using protocol-buffers to access Metrics API.")
cmd.Flags().BoolVar(&o.Sum, "sum", o.Sum, "Print the sum of the resource usage")
cmd.Flags().BoolVar(&o.ShowSwap, "show-swap", o.ShowSwap, "Print pod resources related to swap memory.")
return cmd
}
@ -154,7 +152,7 @@ func (o *TopPodOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []s
o.PodClient = clientset.CoreV1()
o.Printer = metricsutil.NewTopCmdPrinter(o.Out, o.ShowSwap)
o.Printer = metricsutil.NewTopCmdPrinter(o.Out)
return nil
}

View File

@ -168,12 +168,6 @@ func TestTopPod(t *testing.T) {
namespaces: []string{testNS, testNS, testNS},
containers: true,
},
{
name: "with swap",
options: &TopPodOptions{AllNamespaces: true, ShowSwap: true},
namespaces: []string{testNS, "secondtestns", "thirdtestns"},
listsNamespaces: true,
},
}
cmdtesting.InitTestErrorHandler(t)
for _, testCase := range testCases {
@ -290,101 +284,10 @@ func TestTopPod(t *testing.T) {
t.Errorf("containers not matching:\n\texpectedContainers: %v\n\tresultContainers: %v\n", testCase.expectedContainers, resultContainers)
}
}
if testCase.options != nil && testCase.options.ShowSwap {
if !strings.Contains(result, "SWAP(bytes)") {
t.Errorf("missing SWAP(bytes) header: \n%s", result)
}
}
})
}
}
func TestTopPodWithSwap(t *testing.T) {
cmdtesting.InitTestErrorHandler(t)
const testName = "TestTopPodWithSwap"
t.Run(testName, func(t *testing.T) {
metricsList := testV1beta1PodMetricsData()
fakemetricsClientset := &metricsfake.Clientset{}
fakemetricsClientset.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
res := &metricsv1beta1api.PodMetricsList{
Items: metricsList,
}
return true, res, nil
})
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
ns := scheme.Codecs.WithoutConversion()
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path {
case "/api":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: io.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
case "/apis":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: io.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
default:
t.Fatalf("%s: unexpected request: %#v\nGot URL: %#v",
testName, req, req.URL)
return nil, nil
}
}),
}
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdTopPod(tf, nil, streams)
cmdOptions := &TopPodOptions{
ShowSwap: true,
}
cmdOptions.IOStreams = streams
if err := cmdOptions.Complete(tf, cmd, nil); err != nil {
t.Fatal(err)
}
cmdOptions.MetricsClient = fakemetricsClientset
if err := cmdOptions.Validate(); err != nil {
t.Fatal(err)
}
if err := cmdOptions.RunTopPod(); err != nil {
t.Fatal(err)
}
result := buf.String()
expectedSwapBytes := map[string]string{
"pod1": "4Mi",
"pod2": "0Mi",
"pod3": "3Mi",
}
actualSwapBytes := map[string]string{}
for _, line := range strings.Split(result, "\n")[1:] {
lineFields := strings.Fields(line)
if len(lineFields) < 4 {
continue
}
podName := lineFields[0]
swapBytes := lineFields[3]
actualSwapBytes[podName] = swapBytes
}
for expectedPodName, expectedSwapBytes := range expectedSwapBytes {
actualSwapBytes, found := actualSwapBytes[expectedPodName]
if !found {
t.Errorf("missing swap metrics for pod %s", expectedPodName)
}
if actualSwapBytes != expectedSwapBytes {
t.Errorf("unexpected swap metrics for pod %s: expected %s, got %s", expectedPodName, expectedSwapBytes, actualSwapBytes)
}
}
})
}
func getResultColumnValues(result string, columnIndex int) []string {
resultLines := strings.Split(result, "\n")
values := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
@ -507,7 +410,6 @@ func testV1beta1PodMetricsData() []metricsv1beta1api.PodMetrics {
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(1, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(2*(1024*1024), resource.DecimalSI),
"swap": *resource.NewQuantity(1*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(3*(1024*1024), resource.DecimalSI),
},
},
@ -516,7 +418,6 @@ func testV1beta1PodMetricsData() []metricsv1beta1api.PodMetrics {
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(4, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(5*(1024*1024), resource.DecimalSI),
"swap": *resource.NewQuantity(3*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(6*(1024*1024), resource.DecimalSI),
},
},
@ -561,7 +462,6 @@ func testV1beta1PodMetricsData() []metricsv1beta1api.PodMetrics {
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(7, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(8*(1024*1024), resource.DecimalSI),
"swap": *resource.NewQuantity(3*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(9*(1024*1024), resource.DecimalSI),
},
},

View File

@ -30,7 +30,6 @@ import (
"k8s.io/cli-runtime/pkg/genericiooptions"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
metricsv1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1"
"k8s.io/utils/ptr"
)
func TestTopSubcommandsExist(t *testing.T) {
@ -64,7 +63,6 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
Window: metav1.Duration{Duration: time.Minute},
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(1, resource.DecimalSI),
"swap": *resource.NewQuantity(1*(1024*1024), resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(2*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(3*(1024*1024), resource.DecimalSI),
},
@ -74,7 +72,6 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
Window: metav1.Duration{Duration: time.Minute},
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(5, resource.DecimalSI),
"swap": *resource.NewQuantity(2*(1024*1024), resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(6*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(7*(1024*1024), resource.DecimalSI),
},
@ -84,7 +81,6 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
Window: metav1.Duration{Duration: time.Minute},
Usage: v1.ResourceList{
v1.ResourceCPU: *resource.NewMilliQuantity(3, resource.DecimalSI),
"swap": *resource.NewQuantity(0, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(4*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(5*(1024*1024), resource.DecimalSI),
},
@ -104,11 +100,6 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
v1.ResourceMemory: *resource.NewQuantity(20*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(30*(1024*1024), resource.DecimalSI),
},
NodeInfo: v1.NodeSystemInfo{
Swap: &v1.NodeSwapStatus{
Capacity: ptr.To(int64(10 * (1024 * 1024 * 1024))),
},
},
},
},
{
@ -119,11 +110,6 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
v1.ResourceMemory: *resource.NewQuantity(60*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(70*(1024*1024), resource.DecimalSI),
},
NodeInfo: v1.NodeSystemInfo{
Swap: &v1.NodeSwapStatus{
Capacity: ptr.To(int64(20 * (1024 * 1024 * 1024))),
},
},
},
},
{
@ -134,11 +120,6 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
v1.ResourceMemory: *resource.NewQuantity(40*(1024*1024), resource.DecimalSI),
v1.ResourceStorage: *resource.NewQuantity(50*(1024*1024), resource.DecimalSI),
},
NodeInfo: v1.NodeSystemInfo{
Swap: &v1.NodeSwapStatus{
Capacity: ptr.To(int64(30 * (1024 * 1024 * 1024))),
},
},
},
},
},

View File

@ -1,59 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 util
import (
"sync"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/resource"
)
// cachingVerifier wraps the given Verifier to cache return values forever.
type cachingVerifier struct {
cache map[schema.GroupVersionKind]error
mu sync.RWMutex
next resource.Verifier
}
// newCachingVerifier creates a new cache using the given underlying verifier.
func newCachingVerifier(next resource.Verifier) *cachingVerifier {
return &cachingVerifier{
cache: make(map[schema.GroupVersionKind]error),
next: next,
}
}
// HasSupport implements resource.Verifier. It cached return values from the underlying verifier forever.
func (cv *cachingVerifier) HasSupport(gvk schema.GroupVersionKind) error {
// Try to get the cached value.
cv.mu.RLock()
err, ok := cv.cache[gvk]
cv.mu.RUnlock()
if ok {
return err
}
// Cache miss. Get the actual result.
err = cv.next.HasSupport(gvk)
// Update the cache.
cv.mu.Lock()
cv.cache[gvk] = err
cv.mu.Unlock()
return err
}

View File

@ -1,105 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 util
import (
"errors"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type verifierCall struct {
GVK schema.GroupVersionKind
Err error
}
type mockVerifier struct {
t *testing.T
expectedCalls map[schema.GroupVersionKind]error
}
func (m *mockVerifier) CheckExpectations() {
if len(m.expectedCalls) != 0 {
m.t.Errorf("Expected calls remaining: %v", m.expectedCalls)
}
}
func (m *mockVerifier) HasSupport(gvk schema.GroupVersionKind) error {
returnErr, ok := m.expectedCalls[gvk]
if !ok {
m.t.Errorf("Unexpected HasSupport call with GVK=%v", gvk)
}
delete(m.expectedCalls, gvk)
return returnErr
}
func TestCachingVerifier(t *testing.T) {
gvk1 := schema.GroupVersionKind{
Group: "group",
Version: "version",
Kind: "kind",
}
gvk2 := schema.GroupVersionKind{
Group: "group2",
Version: "version2",
Kind: "kind2",
}
err1 := errors.New("some error")
testCases := []struct {
name string
calls []verifierCall
expectedUnderlyingCalls map[schema.GroupVersionKind]error
}{
{
name: "return value is cached",
calls: []verifierCall{
{GVK: gvk1, Err: nil},
{GVK: gvk1, Err: nil},
{GVK: gvk1, Err: nil},
{GVK: gvk2, Err: err1},
{GVK: gvk2, Err: err1},
{GVK: gvk2, Err: err1},
},
expectedUnderlyingCalls: map[schema.GroupVersionKind]error{
gvk1: nil,
gvk2: err1,
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := &mockVerifier{
t: t,
expectedCalls: tc.expectedUnderlyingCalls,
}
verifier := newCachingVerifier(m)
for _, call := range tc.calls {
err := verifier.HasSupport(call.GVK)
if !errors.Is(err, call.Err) {
t.Errorf("Expected error: %v, got: %v", call.Err, err)
}
}
m.CheckExpectations()
})
}
}

View File

@ -172,7 +172,7 @@ func (f *factoryImpl) Validator(validationDirective string) (validation.Schema,
// the discovery client.
oapiV3Client := cached.NewClient(discoveryClient.OpenAPIV3())
queryParam := resource.QueryParamFieldValidation
primary := newCachingVerifier(resource.NewQueryParamVerifierV3(dynamicClient, oapiV3Client, queryParam))
primary := resource.NewQueryParamVerifierV3(dynamicClient, oapiV3Client, queryParam)
secondary := resource.NewQueryParamVerifier(dynamicClient, f.openAPIGetter(), queryParam)
fallback := resource.NewFallbackQueryParamVerifier(primary, secondary)
return validation.NewParamVerifyingSchema(schema, fallback, string(validationDirective)), nil

View File

@ -222,7 +222,7 @@ func checkErr(err error, handleErr func(string, int)) {
func statusCausesToAggrError(scs []metav1.StatusCause) utilerrors.Aggregate {
errs := make([]error, 0, len(scs))
errorMsgs := sets.New[string]()
errorMsgs := sets.NewString()
for _, sc := range scs {
// check for duplicate error messages and skip them
msg := fmt.Sprintf("%s: %s", sc.Field, sc.Message)
@ -425,36 +425,13 @@ func GetPodRunningTimeoutFlag(cmd *cobra.Command) (time.Duration, error) {
type FeatureGate string
const (
// owner: @soltysh
// kep: https://kep.k8s.io/859
//
// HTTP headers with command name and flags used.
CmdHeaders FeatureGate = "KUBECTL_COMMAND_HEADERS"
// owner: @ardaguclu
// kep: https://kep.k8s.io/3104
//
// Separate kubectl user preferences.
KubeRC FeatureGate = "KUBECTL_KUBERC"
// owner: @soltysh
// kep: https://kep.k8s.io/3515
//
// Improved kubectl apply --prune behavior.
OpenAPIV3Patch FeatureGate = "KUBECTL_OPENAPIV3_PATCH"
// owner: @justinb
// kep: https://kep.k8s.io/3659
//
// Improved kubectl apply --prune behavior.
ApplySet FeatureGate = "KUBECTL_APPLYSET"
// owner: @seans
// kep: https://kep.k8s.io/4006
//
// Transition to WebSockets.
ApplySet FeatureGate = "KUBECTL_APPLYSET"
CmdPluginAsSubcommand FeatureGate = "KUBECTL_ENABLE_CMD_SHADOW"
OpenAPIV3Patch FeatureGate = "KUBECTL_OPENAPIV3_PATCH"
RemoteCommandWebsockets FeatureGate = "KUBECTL_REMOTE_COMMAND_WEBSOCKETS"
PortForwardWebsockets FeatureGate = "KUBECTL_PORT_FORWARD_WEBSOCKETS"
// DebugCustomProfile should be dropped in 1.34
DebugCustomProfile FeatureGate = "KUBECTL_DEBUG_CUSTOM_PROFILE"
)
// IsEnabled returns true iff environment variable is set to true.
@ -542,7 +519,7 @@ func AddChunkSizeFlag(cmd *cobra.Command, value *int64) {
}
func AddLabelSelectorFlagVar(cmd *cobra.Command, p *string) {
cmd.Flags().StringVarP(p, "selector", "l", *p, "Selector (label query) to filter on, supports '=', '==', '!=', 'in', 'notin'.(e.g. -l key1=value1,key2=value2,key3 in (value3)). Matching objects must satisfy all of the specified label constraints.")
cmd.Flags().StringVarP(p, "selector", "l", *p, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints.")
}
func AddPruningFlags(cmd *cobra.Command, prune *bool, pruneAllowlist *[]string, all *bool, applySetRef *string) {
@ -561,7 +538,7 @@ func AddPruningFlags(cmd *cobra.Command, prune *bool, pruneAllowlist *[]string,
}
func AddSubresourceFlags(cmd *cobra.Command, subresource *string, usage string) {
cmd.Flags().StringVar(subresource, "subresource", "", usage)
cmd.Flags().StringVar(subresource, "subresource", "", fmt.Sprintf("%s This flag is beta and may change in the future.", usage))
CheckErr(cmd.RegisterFlagCompletionFunc("subresource", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
var commonSubresources = []string{"status", "scale", "resize"}
return commonSubresources, cobra.ShellCompDirectiveNoFileComp

View File

@ -18,10 +18,10 @@ package version
import (
"fmt"
"math"
"io"
"k8s.io/apimachinery/pkg/util/version"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"math"
)
// supportedMinorVersionSkew is the maximum supported difference between the client and server minor versions.
@ -29,26 +29,26 @@ import (
// and server versions 1.18, 1.19, and 1.20 would be within the supported version skew for client version 1.19.
const supportedMinorVersionSkew = 1
// getVersionSkewWarning returns a warning message if the difference between the client and version is greater than
// printVersionSkewWarning prints a warning message if the difference between the client and version is greater than
// the supported version skew.
func getVersionSkewWarning(clientVersion, serverVersion apimachineryversion.Info) (string, error) {
func printVersionSkewWarning(w io.Writer, clientVersion, serverVersion apimachineryversion.Info) error {
parsedClientVersion, err := version.ParseSemantic(clientVersion.GitVersion)
if err != nil {
return "", fmt.Errorf("client version error: %w", err)
return err
}
parsedServerVersion, err := version.ParseSemantic(serverVersion.GitVersion)
if err != nil {
return "", fmt.Errorf("server version error: %w", err)
return err
}
majorVersionDifference := math.Abs(float64(parsedClientVersion.Major()) - float64(parsedServerVersion.Major()))
minorVersionDifference := math.Abs(float64(parsedClientVersion.Minor()) - float64(parsedServerVersion.Minor()))
if majorVersionDifference > 0 || minorVersionDifference > supportedMinorVersionSkew {
warningMessage := fmt.Sprintf("version difference between client (%d.%d) and server (%d.%d) exceeds the supported minor version skew of +/-%d",
fmt.Fprintf(w, "WARNING: version difference between client (%d.%d) and server (%d.%d) exceeds the supported minor version skew of +/-%d\n",
parsedClientVersion.Major(), parsedClientVersion.Minor(), parsedServerVersion.Major(), parsedServerVersion.Minor(), supportedMinorVersionSkew)
return warningMessage, nil
}
return "", nil
return nil
}

View File

@ -17,12 +17,14 @@ limitations under the License.
package version
import (
"testing"
"bytes"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"testing"
)
func TestPrintVersionSkewWarning(t *testing.T) {
output := &bytes.Buffer{}
testCases := []struct {
name string
clientVersion apimachineryversion.Info
@ -80,15 +82,14 @@ func TestPrintVersionSkewWarning(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
warningMessage, err := getVersionSkewWarning(tc.clientVersion, tc.serverVersion)
if err != nil {
t.Errorf("error: %s", err)
}
output.Reset()
if tc.isWarningExpected && warningMessage == "" {
t.Error("warning was expected")
} else if !tc.isWarningExpected && warningMessage != "" {
t.Errorf("warning was not expected. but got %s", warningMessage)
printVersionSkewWarning(output, tc.clientVersion, tc.serverVersion)
if tc.isWarningExpected && output.Len() == 0 {
t.Error("warning was expected, but not written to the output")
} else if !tc.isWarningExpected && output.Len() > 0 {
t.Errorf("warning was not expected, but was written to the output: %s", output.String())
}
})
}

View File

@ -53,9 +53,8 @@ var (
// Options is a struct to support version command
type Options struct {
ClientOnly bool
Output string
WarningsAsErrors bool
ClientOnly bool
Output string
args []string
@ -94,9 +93,6 @@ func NewCmdVersion(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cob
// Complete completes all the required options
func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.WarningsAsErrors = cmd.Flags().Lookup("warnings-as-errors").Value.String() == "true"
if o.ClientOnly {
return nil
}
@ -166,17 +162,11 @@ func (o *Options) Run() error {
}
if versionInfo.ServerVersion != nil {
warningMessage, err := getVersionSkewWarning(*versionInfo.ClientVersion, *versionInfo.ServerVersion)
if err != nil {
if err := printVersionSkewWarning(o.ErrOut, *versionInfo.ClientVersion, *versionInfo.ServerVersion); err != nil {
return err
}
if warningMessage != "" {
if o.WarningsAsErrors {
return errors.New(warningMessage)
}
fmt.Fprintf(o.ErrOut, "Warning: %s\n", warningMessage) //nolint:errcheck
}
}
return serverErr
}

View File

@ -20,6 +20,8 @@ import (
"strings"
"testing"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericiooptions"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
@ -30,18 +32,13 @@ func TestNewCmdVersionClientVersion(t *testing.T) {
defer tf.Cleanup()
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
o := NewOptions(streams)
cmd := NewCmdVersion(tf, streams)
cmd.Flags().Bool("warnings-as-errors", false, "")
if err := o.Complete(tf, cmd, nil); err != nil {
if err := o.Complete(tf, &cobra.Command{}, nil); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if err := o.Validate(); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if err := o.Complete(tf, cmd, []string{"extraParameter0"}); err != nil {
if err := o.Complete(tf, &cobra.Command{}, []string{"extraParameter0"}); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if err := o.Validate(); !strings.Contains(err.Error(), "extra arguments") {

View File

@ -329,9 +329,7 @@ func (o *WaitOptions) RunWait() error {
// or functions from ResourceBuilder for parsing those. Lastly, this poll
// should be replaced with a ListWatch cache.
if err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, o.Timeout, true, func(context.Context) (done bool, err error) {
foundResource := false
visitErr := o.ResourceFinder.Do().Visit(func(info *resource.Info, err error) error {
foundResource = true
return nil
})
if apierrors.IsNotFound(visitErr) {
@ -340,7 +338,7 @@ func (o *WaitOptions) RunWait() error {
if visitErr != nil {
return false, visitErr
}
return foundResource, nil
return true, nil
}); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("%s", wait.ErrWaitTimeout.Error()) // nolint:staticcheck // SA1019

View File

@ -1,12 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
# Disable inheritance as this is an api owners file
options:
no_parent_owners: true
approvers:
- api-approvers
reviewers:
- api-reviewers
- sig-cli-reviewers
labels:
- kind/api-change

View File

@ -1,20 +0,0 @@
/*
Copyright 2024 The Kubernetes Authors.
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.
*/
// +k8s:deepcopy-gen=package
// +groupName=kubectl.config.k8s.io
package config // Package config import "k8s.io/kubectl/pkg/config"

View File

@ -1,33 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 fuzzer
import (
"sigs.k8s.io/randfill"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubectl/pkg/config"
)
// Funcs returns the fuzzer functions for the kubectl apis.
func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
return []interface{}{
func(obj *config.Preference, c randfill.Continue) {
c.FillNoCustom(obj)
},
}
}

View File

@ -1,44 +0,0 @@
/*
Copyright 2024 The Kubernetes Authors.
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 config
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name used in this package
const GroupName = "kubectl.config.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
var (
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme is a global function that registers this API group & version to a scheme
AddToScheme = SchemeBuilder.AddToScheme
)
// addKnownTypes registers known types to the given scheme
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Preference{},
)
return nil
}

View File

@ -1,48 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 scheme
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/kubectl/pkg/config"
"k8s.io/kubectl/pkg/config/v1alpha1"
"k8s.io/kubectl/pkg/config/v1beta1"
)
var (
// Scheme defines methods for serializing and deserializing API objects.
Scheme = runtime.NewScheme()
// StrictCodecs provides methods for retrieving codecs and serializers
// for specific versions and content types.
StrictCodecs = serializer.NewCodecFactory(Scheme, serializer.EnableStrict)
// LenientCodecs provides methods for retrieving codecs and serializers
// for specific versions and content types.
LenientCodecs = serializer.NewCodecFactory(Scheme, serializer.DisableStrict)
)
func init() {
AddToScheme(Scheme)
}
// AddToScheme registers the API group and adds types to a scheme
func AddToScheme(scheme *runtime.Scheme) {
utilruntime.Must(config.AddToScheme(scheme))
utilruntime.Must(v1beta1.AddToScheme(scheme))
utilruntime.Must(v1alpha1.AddToScheme(scheme))
}

View File

@ -1,28 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 scheme
import (
"testing"
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
"k8s.io/kubectl/pkg/config/fuzzer"
)
func TestRoundTripTypes(t *testing.T) {
roundtrip.RoundTripTestForScheme(t, Scheme, fuzzer.Funcs)
}

View File

@ -1,105 +0,0 @@
/*
Copyright 2024 The Kubernetes Authors.
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 config
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Preference stores elements of KubeRC configuration file
type Preference struct {
metav1.TypeMeta
// Defaults allow changing default option values of commands.
// This is especially useful, when user doesn't want to explicitly
// set options each time.
// +optional
Defaults []CommandDefaults
// Aliases allow defining command aliases for existing kubectl commands, with optional default option values.
// If the alias name collides with a built-in command, built-in command always takes precedence.
// Option overrides defined in the defaults section do NOT apply to aliases for the same command.
// kubectl [ALIAS NAME] [USER_OPTIONS] [USER_EXPLICIT_ARGS] expands to
// kubectl [COMMAND] # built-in command alias points to
// [KUBERC_PREPEND_ARGS]
// [USER_OPTIONS]
// [KUBERC_OPTIONS] # rest of the options that are not passed by user in [USER_OPTIONS]
// [USER_EXPLICIT_ARGS]
// [KUBERC_APPEND_ARGS]
// e.g.
// - name: runx
// command: run
// options:
// - name: image
// default: nginx
// appendArgs:
// - --
// - custom-arg1
// For example, if user invokes "kubectl runx test-pod" command,
// this will be expanded to "kubectl run --image=nginx test-pod -- custom-arg1"
// - name: getn
// command: get
// options:
// - name: output
// default: wide
// prependArgs:
// - node
// "kubectl getn control-plane-1" expands to "kubectl get node control-plane-1 --output=wide"
// "kubectl getn control-plane-1 --output=json" expands to "kubectl get node --output=json control-plane-1"
// +optional
Aliases []AliasOverride
}
// AliasOverride stores the alias definitions.
type AliasOverride struct {
// Name is the name of alias that can only include alphabetical characters
// If the alias name conflicts with the built-in command,
// built-in command will be used.
Name string
// Command is the single or set of commands to execute, such as "set env" or "create"
Command string
// PrependArgs stores the arguments such as resource names, etc.
// These arguments are inserted after the alias name.
PrependArgs []string
// AppendArgs stores the arguments such as resource names, etc.
// These arguments are appended to the USER_ARGS.
AppendArgs []string
// Options is allocated to store the option definitions of alias.
// Options only modify the default value of the option and if
// user explicitly passes a value, explicit one is used.
Options []CommandOptionDefault
}
// CommandDefaults stores the commands and their associated option's
// default values.
type CommandDefaults struct {
// Command refers to a command whose flag's default value is changed.
Command string
// Options is a list of options storing different default values.
Options []CommandOptionDefault
}
// CommandOptionDefault stores the name and the specified default
// value of an option.
type CommandOptionDefault struct {
// Option name (long form, without dashes).
Name string
// In a string format of a default value. It will be parsed
// by kubectl to the compatible value of the option.
Default string
}

View File

@ -1,23 +0,0 @@
/*
Copyright 2024 The Kubernetes Authors.
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.
*/
// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +groupName=kubectl.config.k8s.io
// +k8s:conversion-gen=k8s.io/kubectl/pkg/config
// +k8s:defaulter-gen=TypeMeta
package v1alpha1 // Package v1alpha1 import "k8s.io/kubectl/pkg/config/v1alpha1"

View File

@ -1,50 +0,0 @@
/*
Copyright 2024 The Kubernetes Authors.
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 v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name used in this package
const GroupName = "kubectl.config.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
var (
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes)
}
// addKnownTypes registers known types to the given scheme
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Preference{},
)
return nil
}

View File

@ -1,109 +0,0 @@
/*
Copyright 2024 The Kubernetes Authors.
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 v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Preference stores elements of KubeRC configuration file
type Preference struct {
metav1.TypeMeta `json:",inline"`
// overrides allows changing default flag values of commands.
// This is especially useful, when user doesn't want to explicitly
// set flags each time.
// +listType=atomic
Defaults []CommandDefaults `json:"overrides"`
// aliases allow defining command aliases for existing kubectl commands, with optional default flag values.
// If the alias name collides with a built-in command, built-in command always takes precedence.
// Flag overrides defined in the overrides section do NOT apply to aliases for the same command.
// kubectl [ALIAS NAME] [USER_FLAGS] [USER_EXPLICIT_ARGS] expands to
// kubectl [COMMAND] # built-in command alias points to
// [KUBERC_PREPEND_ARGS]
// [USER_FLAGS]
// [KUBERC_FLAGS] # rest of the flags that are not passed by user in [USER_FLAGS]
// [USER_EXPLICIT_ARGS]
// [KUBERC_APPEND_ARGS]
// e.g.
// - name: runx
// command: run
// flags:
// - name: image
// default: nginx
// appendArgs:
// - --
// - custom-arg1
// For example, if user invokes "kubectl runx test-pod" command,
// this will be expanded to "kubectl run --image=nginx test-pod -- custom-arg1"
// - name: getn
// command: get
// flags:
// - name: output
// default: wide
// prependArgs:
// - node
// "kubectl getn control-plane-1" expands to "kubectl get node control-plane-1 --output=wide"
// "kubectl getn control-plane-1 --output=json" expands to "kubectl get node --output=json control-plane-1"
// +listType=atomic
Aliases []AliasOverride `json:"aliases"`
}
// AliasOverride stores the alias definitions.
type AliasOverride struct {
// name is the name of alias that can only include alphabetical characters
// If the alias name conflicts with the built-in command,
// built-in command will be used.
Name string `json:"name"`
// command is the single or set of commands to execute, such as "set env" or "create"
Command string `json:"command"`
// prependArgs stores the arguments such as resource names, etc.
// These arguments are inserted after the alias name.
// +listType=atomic
PrependArgs []string `json:"prependArgs,omitempty"`
// appendArgs stores the arguments such as resource names, etc.
// These arguments are appended to the USER_ARGS.
// +listType=atomic
AppendArgs []string `json:"appendArgs,omitempty"`
// flags is allocated to store the flag definitions of alias.
// flags only modifies the default value of the flag and if
// user explicitly passes a value, explicit one is used.
// +listType=atomic
Options []CommandOptionDefault `json:"flags,omitempty"`
}
// CommandDefaults stores the commands and their associated option's
// default values.
type CommandDefaults struct {
// command refers to a command whose flag's default value is changed.
Command string `json:"command"`
// flags is a list of flags storing different default values.
// +listType=atomic
Options []CommandOptionDefault `json:"flags"`
}
// CommandOptionDefault stores the name and the specified default
// value of an option.
type CommandOptionDefault struct {
// Flag name (long form, without dashes).
Name string `json:"name"`
// In a string format of a default value. It will be parsed
// by kubectl to the compatible value of the flag.
Default string `json:"default"`
}

View File

@ -1,174 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by conversion-gen. DO NOT EDIT.
package v1alpha1
import (
unsafe "unsafe"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
config "k8s.io/kubectl/pkg/config"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*AliasOverride)(nil), (*config.AliasOverride)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_AliasOverride_To_config_AliasOverride(a.(*AliasOverride), b.(*config.AliasOverride), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.AliasOverride)(nil), (*AliasOverride)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_AliasOverride_To_v1alpha1_AliasOverride(a.(*config.AliasOverride), b.(*AliasOverride), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*CommandDefaults)(nil), (*config.CommandDefaults)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_CommandDefaults_To_config_CommandDefaults(a.(*CommandDefaults), b.(*config.CommandDefaults), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.CommandDefaults)(nil), (*CommandDefaults)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CommandDefaults_To_v1alpha1_CommandDefaults(a.(*config.CommandDefaults), b.(*CommandDefaults), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*CommandOptionDefault)(nil), (*config.CommandOptionDefault)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_CommandOptionDefault_To_config_CommandOptionDefault(a.(*CommandOptionDefault), b.(*config.CommandOptionDefault), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.CommandOptionDefault)(nil), (*CommandOptionDefault)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CommandOptionDefault_To_v1alpha1_CommandOptionDefault(a.(*config.CommandOptionDefault), b.(*CommandOptionDefault), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Preference)(nil), (*config.Preference)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_Preference_To_config_Preference(a.(*Preference), b.(*config.Preference), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.Preference)(nil), (*Preference)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_Preference_To_v1alpha1_Preference(a.(*config.Preference), b.(*Preference), scope)
}); err != nil {
return err
}
return nil
}
func autoConvert_v1alpha1_AliasOverride_To_config_AliasOverride(in *AliasOverride, out *config.AliasOverride, s conversion.Scope) error {
out.Name = in.Name
out.Command = in.Command
out.PrependArgs = *(*[]string)(unsafe.Pointer(&in.PrependArgs))
out.AppendArgs = *(*[]string)(unsafe.Pointer(&in.AppendArgs))
out.Options = *(*[]config.CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_v1alpha1_AliasOverride_To_config_AliasOverride is an autogenerated conversion function.
func Convert_v1alpha1_AliasOverride_To_config_AliasOverride(in *AliasOverride, out *config.AliasOverride, s conversion.Scope) error {
return autoConvert_v1alpha1_AliasOverride_To_config_AliasOverride(in, out, s)
}
func autoConvert_config_AliasOverride_To_v1alpha1_AliasOverride(in *config.AliasOverride, out *AliasOverride, s conversion.Scope) error {
out.Name = in.Name
out.Command = in.Command
out.PrependArgs = *(*[]string)(unsafe.Pointer(&in.PrependArgs))
out.AppendArgs = *(*[]string)(unsafe.Pointer(&in.AppendArgs))
out.Options = *(*[]CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_config_AliasOverride_To_v1alpha1_AliasOverride is an autogenerated conversion function.
func Convert_config_AliasOverride_To_v1alpha1_AliasOverride(in *config.AliasOverride, out *AliasOverride, s conversion.Scope) error {
return autoConvert_config_AliasOverride_To_v1alpha1_AliasOverride(in, out, s)
}
func autoConvert_v1alpha1_CommandDefaults_To_config_CommandDefaults(in *CommandDefaults, out *config.CommandDefaults, s conversion.Scope) error {
out.Command = in.Command
out.Options = *(*[]config.CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_v1alpha1_CommandDefaults_To_config_CommandDefaults is an autogenerated conversion function.
func Convert_v1alpha1_CommandDefaults_To_config_CommandDefaults(in *CommandDefaults, out *config.CommandDefaults, s conversion.Scope) error {
return autoConvert_v1alpha1_CommandDefaults_To_config_CommandDefaults(in, out, s)
}
func autoConvert_config_CommandDefaults_To_v1alpha1_CommandDefaults(in *config.CommandDefaults, out *CommandDefaults, s conversion.Scope) error {
out.Command = in.Command
out.Options = *(*[]CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_config_CommandDefaults_To_v1alpha1_CommandDefaults is an autogenerated conversion function.
func Convert_config_CommandDefaults_To_v1alpha1_CommandDefaults(in *config.CommandDefaults, out *CommandDefaults, s conversion.Scope) error {
return autoConvert_config_CommandDefaults_To_v1alpha1_CommandDefaults(in, out, s)
}
func autoConvert_v1alpha1_CommandOptionDefault_To_config_CommandOptionDefault(in *CommandOptionDefault, out *config.CommandOptionDefault, s conversion.Scope) error {
out.Name = in.Name
out.Default = in.Default
return nil
}
// Convert_v1alpha1_CommandOptionDefault_To_config_CommandOptionDefault is an autogenerated conversion function.
func Convert_v1alpha1_CommandOptionDefault_To_config_CommandOptionDefault(in *CommandOptionDefault, out *config.CommandOptionDefault, s conversion.Scope) error {
return autoConvert_v1alpha1_CommandOptionDefault_To_config_CommandOptionDefault(in, out, s)
}
func autoConvert_config_CommandOptionDefault_To_v1alpha1_CommandOptionDefault(in *config.CommandOptionDefault, out *CommandOptionDefault, s conversion.Scope) error {
out.Name = in.Name
out.Default = in.Default
return nil
}
// Convert_config_CommandOptionDefault_To_v1alpha1_CommandOptionDefault is an autogenerated conversion function.
func Convert_config_CommandOptionDefault_To_v1alpha1_CommandOptionDefault(in *config.CommandOptionDefault, out *CommandOptionDefault, s conversion.Scope) error {
return autoConvert_config_CommandOptionDefault_To_v1alpha1_CommandOptionDefault(in, out, s)
}
func autoConvert_v1alpha1_Preference_To_config_Preference(in *Preference, out *config.Preference, s conversion.Scope) error {
out.Defaults = *(*[]config.CommandDefaults)(unsafe.Pointer(&in.Defaults))
out.Aliases = *(*[]config.AliasOverride)(unsafe.Pointer(&in.Aliases))
return nil
}
// Convert_v1alpha1_Preference_To_config_Preference is an autogenerated conversion function.
func Convert_v1alpha1_Preference_To_config_Preference(in *Preference, out *config.Preference, s conversion.Scope) error {
return autoConvert_v1alpha1_Preference_To_config_Preference(in, out, s)
}
func autoConvert_config_Preference_To_v1alpha1_Preference(in *config.Preference, out *Preference, s conversion.Scope) error {
out.Defaults = *(*[]CommandDefaults)(unsafe.Pointer(&in.Defaults))
out.Aliases = *(*[]AliasOverride)(unsafe.Pointer(&in.Aliases))
return nil
}
// Convert_config_Preference_To_v1alpha1_Preference is an autogenerated conversion function.
func Convert_config_Preference_To_v1alpha1_Preference(in *config.Preference, out *Preference, s conversion.Scope) error {
return autoConvert_config_Preference_To_v1alpha1_Preference(in, out, s)
}

View File

@ -1,133 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AliasOverride) DeepCopyInto(out *AliasOverride) {
*out = *in
if in.PrependArgs != nil {
in, out := &in.PrependArgs, &out.PrependArgs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.AppendArgs != nil {
in, out := &in.AppendArgs, &out.AppendArgs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Options != nil {
in, out := &in.Options, &out.Options
*out = make([]CommandOptionDefault, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasOverride.
func (in *AliasOverride) DeepCopy() *AliasOverride {
if in == nil {
return nil
}
out := new(AliasOverride)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommandDefaults) DeepCopyInto(out *CommandDefaults) {
*out = *in
if in.Options != nil {
in, out := &in.Options, &out.Options
*out = make([]CommandOptionDefault, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandDefaults.
func (in *CommandDefaults) DeepCopy() *CommandDefaults {
if in == nil {
return nil
}
out := new(CommandDefaults)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommandOptionDefault) DeepCopyInto(out *CommandOptionDefault) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandOptionDefault.
func (in *CommandOptionDefault) DeepCopy() *CommandOptionDefault {
if in == nil {
return nil
}
out := new(CommandOptionDefault)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Preference) DeepCopyInto(out *Preference) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Defaults != nil {
in, out := &in.Defaults, &out.Defaults
*out = make([]CommandDefaults, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Aliases != nil {
in, out := &in.Aliases, &out.Aliases
*out = make([]AliasOverride, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Preference.
func (in *Preference) DeepCopy() *Preference {
if in == nil {
return nil
}
out := new(Preference)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Preference) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@ -1,33 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by defaulter-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@ -1,23 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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.
*/
// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +groupName=kubectl.config.k8s.io
// +k8s:conversion-gen=k8s.io/kubectl/pkg/config
// +k8s:defaulter-gen=TypeMeta
package v1beta1 // Package v1beta1 import "k8s.io/kubectl/pkg/config/v1beta1"

View File

@ -1,50 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 v1beta1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name used in this package
const GroupName = "kubectl.config.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
var (
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes)
}
// addKnownTypes registers known types to the given scheme
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Preference{},
)
return nil
}

View File

@ -1,109 +0,0 @@
/*
Copyright 2025 The Kubernetes Authors.
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 v1beta1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Preference stores elements of KubeRC configuration file
type Preference struct {
metav1.TypeMeta `json:",inline"`
// defaults allow changing default option values of commands.
// This is especially useful, when user doesn't want to explicitly
// set options each time.
// +listType=atomic
Defaults []CommandDefaults `json:"defaults"`
// aliases allow defining command aliases for existing kubectl commands, with optional default option values.
// If the alias name collides with a built-in command, built-in command always takes precedence.
// Option overrides defined in the defaults section do NOT apply to aliases for the same command.
// kubectl [ALIAS NAME] [USER_OPTIONS] [USER_EXPLICIT_ARGS] expands to
// kubectl [COMMAND] # built-in command alias points to
// [KUBERC_PREPEND_ARGS]
// [USER_OPTIONS]
// [KUBERC_OPTIONS] # rest of the options that are not passed by user in [USER_OPTIONS]
// [USER_EXPLICIT_ARGS]
// [KUBERC_APPEND_ARGS]
// e.g.
// - name: runx
// command: run
// options:
// - name: image
// default: nginx
// appendArgs:
// - --
// - custom-arg1
// For example, if user invokes "kubectl runx test-pod" command,
// this will be expanded to "kubectl run --image=nginx test-pod -- custom-arg1"
// - name: getn
// command: get
// options:
// - name: output
// default: wide
// prependArgs:
// - node
// "kubectl getn control-plane-1" expands to "kubectl get node control-plane-1 --output=wide"
// "kubectl getn control-plane-1 --output=json" expands to "kubectl get node --output=json control-plane-1"
// +listType=atomic
Aliases []AliasOverride `json:"aliases"`
}
// AliasOverride stores the alias definitions.
type AliasOverride struct {
// name is the name of alias that can only include alphabetical characters
// If the alias name conflicts with the built-in command,
// built-in command will be used.
Name string `json:"name"`
// command is the single or set of commands to execute, such as "set env" or "create"
Command string `json:"command"`
// prependArgs stores the arguments such as resource names, etc.
// These arguments are inserted after the alias name.
// +listType=atomic
PrependArgs []string `json:"prependArgs,omitempty"`
// appendArgs stores the arguments such as resource names, etc.
// These arguments are appended to the USER_ARGS.
// +listType=atomic
AppendArgs []string `json:"appendArgs,omitempty"`
// options is allocated to store the option definitions of alias.
// options only modify the default value of the option and if
// user explicitly passes a value, explicit one is used.
// +listType=atomic
Options []CommandOptionDefault `json:"options,omitempty"`
}
// CommandDefaults stores the commands and their associated option's
// default values.
type CommandDefaults struct {
// command refers to a command whose option's default value is changed.
Command string `json:"command"`
// options is a list of options storing different default values.
// +listType=atomic
Options []CommandOptionDefault `json:"options"`
}
// CommandOptionDefault stores the name and the specified default
// value of an option.
type CommandOptionDefault struct {
// Option name (long form, without dashes).
Name string `json:"name"`
// In a string format of a default value. It will be parsed
// by kubectl to the compatible value of the option.
Default string `json:"default"`
}

View File

@ -1,174 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by conversion-gen. DO NOT EDIT.
package v1beta1
import (
unsafe "unsafe"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
config "k8s.io/kubectl/pkg/config"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*AliasOverride)(nil), (*config.AliasOverride)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_AliasOverride_To_config_AliasOverride(a.(*AliasOverride), b.(*config.AliasOverride), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.AliasOverride)(nil), (*AliasOverride)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_AliasOverride_To_v1beta1_AliasOverride(a.(*config.AliasOverride), b.(*AliasOverride), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*CommandDefaults)(nil), (*config.CommandDefaults)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_CommandDefaults_To_config_CommandDefaults(a.(*CommandDefaults), b.(*config.CommandDefaults), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.CommandDefaults)(nil), (*CommandDefaults)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CommandDefaults_To_v1beta1_CommandDefaults(a.(*config.CommandDefaults), b.(*CommandDefaults), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*CommandOptionDefault)(nil), (*config.CommandOptionDefault)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_CommandOptionDefault_To_config_CommandOptionDefault(a.(*CommandOptionDefault), b.(*config.CommandOptionDefault), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.CommandOptionDefault)(nil), (*CommandOptionDefault)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CommandOptionDefault_To_v1beta1_CommandOptionDefault(a.(*config.CommandOptionDefault), b.(*CommandOptionDefault), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Preference)(nil), (*config.Preference)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_Preference_To_config_Preference(a.(*Preference), b.(*config.Preference), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.Preference)(nil), (*Preference)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_Preference_To_v1beta1_Preference(a.(*config.Preference), b.(*Preference), scope)
}); err != nil {
return err
}
return nil
}
func autoConvert_v1beta1_AliasOverride_To_config_AliasOverride(in *AliasOverride, out *config.AliasOverride, s conversion.Scope) error {
out.Name = in.Name
out.Command = in.Command
out.PrependArgs = *(*[]string)(unsafe.Pointer(&in.PrependArgs))
out.AppendArgs = *(*[]string)(unsafe.Pointer(&in.AppendArgs))
out.Options = *(*[]config.CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_v1beta1_AliasOverride_To_config_AliasOverride is an autogenerated conversion function.
func Convert_v1beta1_AliasOverride_To_config_AliasOverride(in *AliasOverride, out *config.AliasOverride, s conversion.Scope) error {
return autoConvert_v1beta1_AliasOverride_To_config_AliasOverride(in, out, s)
}
func autoConvert_config_AliasOverride_To_v1beta1_AliasOverride(in *config.AliasOverride, out *AliasOverride, s conversion.Scope) error {
out.Name = in.Name
out.Command = in.Command
out.PrependArgs = *(*[]string)(unsafe.Pointer(&in.PrependArgs))
out.AppendArgs = *(*[]string)(unsafe.Pointer(&in.AppendArgs))
out.Options = *(*[]CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_config_AliasOverride_To_v1beta1_AliasOverride is an autogenerated conversion function.
func Convert_config_AliasOverride_To_v1beta1_AliasOverride(in *config.AliasOverride, out *AliasOverride, s conversion.Scope) error {
return autoConvert_config_AliasOverride_To_v1beta1_AliasOverride(in, out, s)
}
func autoConvert_v1beta1_CommandDefaults_To_config_CommandDefaults(in *CommandDefaults, out *config.CommandDefaults, s conversion.Scope) error {
out.Command = in.Command
out.Options = *(*[]config.CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_v1beta1_CommandDefaults_To_config_CommandDefaults is an autogenerated conversion function.
func Convert_v1beta1_CommandDefaults_To_config_CommandDefaults(in *CommandDefaults, out *config.CommandDefaults, s conversion.Scope) error {
return autoConvert_v1beta1_CommandDefaults_To_config_CommandDefaults(in, out, s)
}
func autoConvert_config_CommandDefaults_To_v1beta1_CommandDefaults(in *config.CommandDefaults, out *CommandDefaults, s conversion.Scope) error {
out.Command = in.Command
out.Options = *(*[]CommandOptionDefault)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_config_CommandDefaults_To_v1beta1_CommandDefaults is an autogenerated conversion function.
func Convert_config_CommandDefaults_To_v1beta1_CommandDefaults(in *config.CommandDefaults, out *CommandDefaults, s conversion.Scope) error {
return autoConvert_config_CommandDefaults_To_v1beta1_CommandDefaults(in, out, s)
}
func autoConvert_v1beta1_CommandOptionDefault_To_config_CommandOptionDefault(in *CommandOptionDefault, out *config.CommandOptionDefault, s conversion.Scope) error {
out.Name = in.Name
out.Default = in.Default
return nil
}
// Convert_v1beta1_CommandOptionDefault_To_config_CommandOptionDefault is an autogenerated conversion function.
func Convert_v1beta1_CommandOptionDefault_To_config_CommandOptionDefault(in *CommandOptionDefault, out *config.CommandOptionDefault, s conversion.Scope) error {
return autoConvert_v1beta1_CommandOptionDefault_To_config_CommandOptionDefault(in, out, s)
}
func autoConvert_config_CommandOptionDefault_To_v1beta1_CommandOptionDefault(in *config.CommandOptionDefault, out *CommandOptionDefault, s conversion.Scope) error {
out.Name = in.Name
out.Default = in.Default
return nil
}
// Convert_config_CommandOptionDefault_To_v1beta1_CommandOptionDefault is an autogenerated conversion function.
func Convert_config_CommandOptionDefault_To_v1beta1_CommandOptionDefault(in *config.CommandOptionDefault, out *CommandOptionDefault, s conversion.Scope) error {
return autoConvert_config_CommandOptionDefault_To_v1beta1_CommandOptionDefault(in, out, s)
}
func autoConvert_v1beta1_Preference_To_config_Preference(in *Preference, out *config.Preference, s conversion.Scope) error {
out.Defaults = *(*[]config.CommandDefaults)(unsafe.Pointer(&in.Defaults))
out.Aliases = *(*[]config.AliasOverride)(unsafe.Pointer(&in.Aliases))
return nil
}
// Convert_v1beta1_Preference_To_config_Preference is an autogenerated conversion function.
func Convert_v1beta1_Preference_To_config_Preference(in *Preference, out *config.Preference, s conversion.Scope) error {
return autoConvert_v1beta1_Preference_To_config_Preference(in, out, s)
}
func autoConvert_config_Preference_To_v1beta1_Preference(in *config.Preference, out *Preference, s conversion.Scope) error {
out.Defaults = *(*[]CommandDefaults)(unsafe.Pointer(&in.Defaults))
out.Aliases = *(*[]AliasOverride)(unsafe.Pointer(&in.Aliases))
return nil
}
// Convert_config_Preference_To_v1beta1_Preference is an autogenerated conversion function.
func Convert_config_Preference_To_v1beta1_Preference(in *config.Preference, out *Preference, s conversion.Scope) error {
return autoConvert_config_Preference_To_v1beta1_Preference(in, out, s)
}

View File

@ -1,133 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1beta1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AliasOverride) DeepCopyInto(out *AliasOverride) {
*out = *in
if in.PrependArgs != nil {
in, out := &in.PrependArgs, &out.PrependArgs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.AppendArgs != nil {
in, out := &in.AppendArgs, &out.AppendArgs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Options != nil {
in, out := &in.Options, &out.Options
*out = make([]CommandOptionDefault, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasOverride.
func (in *AliasOverride) DeepCopy() *AliasOverride {
if in == nil {
return nil
}
out := new(AliasOverride)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommandDefaults) DeepCopyInto(out *CommandDefaults) {
*out = *in
if in.Options != nil {
in, out := &in.Options, &out.Options
*out = make([]CommandOptionDefault, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandDefaults.
func (in *CommandDefaults) DeepCopy() *CommandDefaults {
if in == nil {
return nil
}
out := new(CommandDefaults)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommandOptionDefault) DeepCopyInto(out *CommandOptionDefault) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandOptionDefault.
func (in *CommandOptionDefault) DeepCopy() *CommandOptionDefault {
if in == nil {
return nil
}
out := new(CommandOptionDefault)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Preference) DeepCopyInto(out *Preference) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Defaults != nil {
in, out := &in.Defaults, &out.Defaults
*out = make([]CommandDefaults, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Aliases != nil {
in, out := &in.Aliases, &out.Aliases
*out = make([]AliasOverride, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Preference.
func (in *Preference) DeepCopy() *Preference {
if in == nil {
return nil
}
out := new(Preference)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Preference) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

Some files were not shown because too many files have changed in this diff Show More