Compare commits

...

410 Commits

Author SHA1 Message Date
Kubernetes Publisher 2da25b2322 Merge pull request #132269 from dims/update-to-latest-github.com/modern-go/reflect2
Update to latest github.com/modern-go/reflect2

Kubernetes-commit: d55b119d34883bbad2a3436dcb6c62339d963031
2025-06-12 21:02:18 +00:00
Kubernetes Publisher 110ba5998e Merge pull request #132251 from ardaguclu/kubectl-interactive-delete-fix
kubectl delete: update interactive delete to break on new line

Kubernetes-commit: dac3c09bd16643dbac5e976e85d81825dd226ac0
2025-06-12 16:46:28 +00:00
Davanum Srinivas 716737e46a Update to latest github.com/modern-go/reflect2
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 3908550c0dc189cfa9de38a84bee508fa0659463
2025-06-12 11:20:39 -04:00
Arda Güçlü 8a11631ed9 kubectl delete: Update interactive delete to break on new line
Kubernetes-commit: fb611f4c93e6d8d8eb920f4436af748432402f50
2025-06-12 11:27:51 +03:00
Kubernetes Publisher 330f86df8e Merge pull request #132209 from dims/update-github.com/spf13/cobra-v1.9.1eksctl
update github.com/spf13/cobra v1.9.1

Kubernetes-commit: dc19f0b6b9cd14ece6b1929cb4e7ea2c9d322b95
2025-06-10 20:54:36 +00:00
Kubernetes Publisher 55101ca654 Merge pull request #131500 from HaraldNordgren/sort_configmaps
kubectl: sort configmap data alphabetically and simplify display format

Kubernetes-commit: 447efd4c0f45f13d262423265a8a960666ed3778
2025-06-10 20:54:34 +00:00
Harald Nordgren ab62ac8cf1 Revert "improve display format"
This reverts commit 28e7acf0f93f5c9edb43ab09cd181e8847409215.

Kubernetes-commit: f8b701243503fc10a037f86e77ce4df5741a07c6
2025-06-10 16:56:58 +02:00
Davanum Srinivas af5ade99d8 update github.com/spf13/cobra v1.9.1
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 449320a54a2dac04f953d5f6401d875ea9b7e8de
2025-06-10 10:50:54 -04:00
Kubernetes Publisher 4d27286e9c Merge pull request #132103 from nojnhuh/typed-ring-buffer
Replace queue.FIFOs with k8s.io/utils/buffer.Ring

Kubernetes-commit: 5090812df4fb6cf09a9181635d90c2e154eab8cc
2025-06-06 21:12:11 +00:00
Kubernetes Publisher 9130183f39 Merge pull request #132110 from jpbetz/gengo-bump
Bump gengo/v2 to latest, pick up related validation-gen fixes

Kubernetes-commit: 4fff091ce7c8b22e6a511231e400adb865a7b300
2025-06-05 21:39:08 +00:00
Joe Betz e808dbbf1f Bump gengo/v2 to latest
Kubernetes-commit: ac5cb23000f57b7b034fa98e5cc4f6e8fb6e8a9c
2025-06-04 22:39:08 -04:00
Jon Huhn 579a7a5a35 Update k8s.io/utils for new generic ring buffer
Kubernetes-commit: 8cdbbf5cdaef7e37cfd432e9044aa52f4d42adcd
2025-06-04 12:09:53 -05:00
Itamar Holder 0b4adb247f [KEP-2400] kubectl top: add a --show-swap option (#129458)
* top, refactor: turn package-exposed variables to unexpose struct fields

Signed-off-by: Itamar Holder <iholder@redhat.com>

* kubectl top node: add the --show-swap option

Example output:
> kubectl top node --show-swap
NAME     CPU(cores)   CPU(%)   MEMORY(bytes)   MEMORY(%)   SWAP(bytes)   SWAP(%)
node01   500m         8%       2836Mi          60%         0Mi           0%
node02   260m         5%       2206Mi          47%         512Mi         50%

Signed-off-by: Itamar Holder <iholder@redhat.com>

* kubectl top pod: add the --show-swap option

Example output:
> kubectl top pod -n kube-system --show-swap
NAME                                      CPU(cores)   MEMORY(bytes)   SWAP(bytes)
coredns-58d5bc5cdb-5nbk4                  2m           19Mi            0Mi
coredns-58d5bc5cdb-jsh26                  3m           37Mi            0Mi
etcd-node01                               51m          143Mi           0Mi
kube-apiserver-node01                     98m          824Mi           0Mi
kube-controller-manager-node01            20m          135Mi           0Mi
kube-proxy-ffgs2                          1m           24Mi            0Mi
kube-proxy-fhvwx                          1m           39Mi            0Mi
kube-scheduler-node01                     13m          69Mi            0Mi
metrics-server-8598789fdb-d2kcj           5m           26Mi            0Mi

Signed-off-by: Itamar Holder <iholder@redhat.com>

* kubectl top node --show-swap: add unit tests

Signed-off-by: Itamar Holder <iholder@redhat.com>

* kubectl top pod --show-swap: Add unit tests

Signed-off-by: Itamar Holder <iholder@redhat.com>

* Explicitly mark swap as unavailable when necessary

Signed-off-by: Itamar Holder <iholder@redhat.com>

---------

Signed-off-by: Itamar Holder <iholder@redhat.com>

Kubernetes-commit: 8d3fb9ee0a51b6a6ea135d991391c35806422c19
2025-06-04 17:10:38 +03:00
Kubernetes Publisher 49afb3c466 Merge pull request #132055 from soltysh/default_prefs_tests
kuberc: add tests for DefaultGetPreferences

Kubernetes-commit: e9b3d62c9aa2c25d745fdf56a7ce5b29ff72973d
2025-06-03 20:43:23 +00:00
Maciej Szulik 17c0dde6b1 kuberc: add tests for DefaultGetPreferences
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 68efb079aabd3295ff4ee5cc56c89ff266e9224d
2025-06-02 16:47:02 +02:00
Kubernetes Publisher bc4c094b08 Merge pull request #131984 from soltysh/update_sigcli_security
Update security contacts for sig-cli owned repos

Kubernetes-commit: cefa8311bca466462734d9c1a24e549e7f94ba19
2025-05-28 18:35:03 +00:00
Kubernetes Publisher 800afb48a7 Merge pull request #131951 from dims/drop-usages-of-deprecated-otelgrpc-methods
Drop usages of deprecated otelgrpc methods (update to v0.60.0)

Kubernetes-commit: d9c1b4ec9b3df7f09dc23a0cc2b3daf2506d3688
2025-05-27 18:46:20 +00:00
Maciej Szulik 2375a3a9f6 Update security contacts for sig-cli owned repos
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 4e3634bbbfb2e416d991075a2a99ab92b0e3da19
2025-05-27 16:51:51 +02:00
Kubernetes Publisher 18f24e791d Merge pull request #131964 from skitt/kubectl-pkg-errors
kubectl: drop dependency on github.com/pkg/errors

Kubernetes-commit: 4c2a741aacc6eea0ae1b0b345034434f9473f52b
2025-05-26 23:12:30 +00:00
Kubernetes Publisher 9c13527bac Merge pull request #131962 from superbrothers/kubectl-explain-revert-output-shorthand
Revert shorthand for kubectl explain --output

Kubernetes-commit: b2dfba4151b859c31a27fe31f8703f9b2b758270
2025-05-26 18:33:18 +00:00
Kubernetes Publisher 17bb82b84d Merge pull request #131818 from soltysh/kuberc_beta
Promote kuberc to beta

Kubernetes-commit: fe5b9896ae8601b044a4e47901a844c93070df3b
2025-05-26 14:50:31 +00:00
Stephen Kitt abe43f6e92 kubectl: drop dependency on github.com/pkg/errors
The package is unmaintained, and kubectl doesn't rely on the
functionality it provides on top of Golang errors (stack traces).

Signed-off-by: Stephen Kitt <skitt@redhat.com>

Kubernetes-commit: 54b2fad0330032ae1bbac990f93a3644aa8a12af
2025-05-26 10:44:46 +02:00
Kazuki Suda bb9c5182ea Revert shorthand for kubectl explain --output
Kubernetes-commit: df2857e7777f18c482359cfb43a72a3cdfd89646
2025-05-26 12:16:24 +09:00
Davanum Srinivas 4ee16d2b51 Drop usages of deprecated otelgrpc methods
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 7c0f968ab256486b524ea37014ccf580b12c73e4
2025-05-23 19:40:36 -07:00
Maciej Szulik 46d6f63709 kuberc: make update and update-vendor
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 76f95271a5d563ea31edbcd8f0e8eebf67cb3634
2025-05-15 14:15:20 +02:00
Maciej Szulik 8500d2979d kuberc: introduce fuzzing for kuberc types
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: c29accaf5819bd4b05409cecb9bbb3ba065d840b
2025-05-16 13:45:37 +02:00
Arda Güçlü ca5a831a47 Promote kuberc to beta
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: b0370c483af1bdbc1e2664f53445411c585c4559
2025-05-06 12:52:20 +03:00
Maciej Szulik b011cffff8 kuberc: pick the first known version when decoding + tests
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 1f355e5b44141be55da269a9183d53bbccd16c95
2025-05-15 16:24:43 +02:00
Maciej Szulik cb7efba696 kuberc: align internal and v1alpha1 go-types with v1beta1
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 0341b27c5d0dfb1d10818c9976f54af22971bedc
2025-05-21 13:32:37 +02:00
Maciej Szulik 2be4847754 kuberc: add v1beta1 types
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 39195f9a463cce6b3ce4e3d9f648c2915407596d
2025-05-15 14:14:59 +02:00
Kubernetes Publisher 6096dfa3cf Merge pull request #131741 from soltysh/deprecate_preferences
Deprecate kubeconfig's preference field in favor of kuberc

Kubernetes-commit: c40db09a0a2bf8df02be93d7da1912cfa7cbe333
2025-05-20 16:37:25 +00:00
Kubernetes Publisher 279ddf3abe Merge pull request #131838 from dims/bump-google.golang.org/grpc-to-google-v1.72.1
Bump google.golang.org/grpc to google v1.72.1

Kubernetes-commit: 444e2b4eb079727d7cdd81ad25041502656370b8
2025-05-20 16:37:21 +00:00
Omer Aplatony 5ff92a69e3 Kubectl: check version skew (#127365)
Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: 35307319740a3a52cf4632c24b7f99d675537bdf
2025-05-19 20:19:14 +03:00
Davanum Srinivas 777f5e3cd1 Bump google.golang.org/grpc v1.72.1
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 9b3830fba234bc4a4f09a1ad4417e4d18b74d6dc
2025-05-18 12:52:05 -04:00
Kubernetes Publisher 4afda566a9 Merge pull request #128419 from liggitt/etcd-3.6
etcd 3.6 client update

Kubernetes-commit: 09ca440a450e9103a8f835f598c09237dba6ecbb
2025-05-16 04:42:29 +00:00
Jordan Liggitt c37ca76b9c bump etcd client to 3.6
hack/pin-dependency.sh go.etcd.io/etcd/api/v3 v3.6.0
hack/pin-dependency.sh go.etcd.io/etcd/client/pkg/v3 v3.6.0
hack/pin-dependency.sh go.etcd.io/etcd/client/v3 v3.6.0
hack/pin-dependency.sh go.etcd.io/etcd/pkg/v3 v3.6.0
hack/pin-dependency.sh go.etcd.io/etcd/server/v3 v3.6.0

hack/pin-dependency.sh github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0

hack/update-vendor.sh

Kubernetes-commit: cf0bbf1171e918d5d7ba1d3c83b5f347fc8333b0
2025-05-15 21:19:11 -04:00
Maciej Szulik 47f13bd18b Deprecate kubeconfig's preference field in favor of kuberc
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 8cf5e8db78deb186ef362f64ab779c09e9520156
2025-05-13 13:39:13 +02:00
Kubernetes Publisher 88bb12ba04 Merge pull request #131672 from soltysh/kubectl_featuregate_cleanup
Kubectl FeatureGate cleanups

Kubernetes-commit: 8812a3dc3ed1cbd3c7dc38b8027e014672cf1fb1
2025-05-08 13:21:14 -07:00
Maciej Szulik 52ec1da081 Add comment describing the feature gate with a link to KEP
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 9e3a1b0a9081ab49bbc44c415525dce862eb6a12
2025-05-08 14:43:24 +02:00
Maciej Szulik 307936eb9d Swap KUBECTL_COMMAND_HEADERS to use the proper feature gate mechanism
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: e3f3da5e795960508089aed08fe7fd9bec0a6db2
2025-05-08 14:09:17 +02:00
Maciej Szulik 90ee929b88 Drop KUBECTL_ENABLE_CMD_SHADOW featgure gat entirely
https://kep.k8s.io/3638 has been promoted to stable back in 1.32 so now
is the right time to drop this feature gate entirely.

Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: d1b5f268b48eda4bb8acdeef52407c27add9e076
2025-05-08 14:05:19 +02:00
Kubernetes Publisher 105c831190 Merge pull request #131668 from soltysh/command_creation_logging
Manually read verbosity before kubectl command construction

Kubernetes-commit: 4e30b51ebcdc24a65a0a5edfde0b9706c95d43d0
2025-05-08 20:24:14 +00:00
Maciej Szulik d35aa2c630 Manually read verbosity before kubectl command construction
kubectl command construction is slowly getting more functionality which
sometimes requires to log certain actions. Currently we parse the
verbosity only when actually running the command, so all of construction
code is not able to use -v=5. This commit adds the manual parsing and
loglevel setting berore we even start creating the kubectl command.

Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 69682b75e508462e01f865a156f2171233b653d1
2025-05-08 13:29:11 +02:00
Kubernetes Publisher f4a8c5b53e Merge pull request #131620 from ardaguclu/drop-custom-profile-feature
Drop KUBECTL_DEBUG_CUSTOM_PROFILE feature gate entirely

Kubernetes-commit: 8b00a96b51e82075be9770282c9c82507d8abf38
2025-05-07 16:19:08 +00:00
Arda Güçlü 5bcd2add11 Drop KUBECTL_DEBUG_CUSTOM_PROFILE feature gate entirely
Kubernetes-commit: 94d043b149b845a4f02f12a3d318df278194d377
2025-05-06 13:00:14 +03:00
Kubernetes Publisher bb3c0d9f3a Merge pull request #131586 from ardaguclu/kuberc-completion
Continue alias creation when __completion is used to enable completion

Kubernetes-commit: 893486dfd16ff8c628c6f33bb2bea869ad86115f
2025-05-05 08:19:24 +00:00
Kubernetes Publisher 3323e167c5 Merge pull request #131595 from aojea/utils_fake_clock
update k8s.io/utils to bring fakeClock.Waiters()

Kubernetes-commit: e3e1f80c0110c847acf4381b1790c1c667395010
2025-05-03 04:20:15 +00:00
Antonio Ojea 3013d81bdf update k8s.io/utils to bring fakeClock.Waiters()
Change-Id: I7e25338df225c2c27457403fbc2f158d08638f87

Kubernetes-commit: c2c003a71fc52fa79c2fff0109afad58573d0216
2025-05-02 11:21:11 +00:00
Kubernetes Publisher 38e8d36c38 Merge pull request #130989 from liggitt/creationTimestamp-omitzero
Omit null creationTimestamp

Kubernetes-commit: 01899a7c86337b05a16a4155c9351cf947beaee9
2025-05-03 00:24:11 +00:00
Arda Güçlü b0f5f0c0aa Continue alias creation when __completion is used to enable completion
Kubernetes-commit: f6d0498017fc71c72891ad9455c4391aa63c6e71
2025-05-02 13:23:22 +03:00
Harald Nordgren 65d852d39c improve display format
Kubernetes-commit: 28e7acf0f93f5c9edb43ab09cd181e8847409215
2025-04-27 20:35:38 +02:00
Harald Nordgren 7ec7bb7cc1 kubectl: sort configmaps alphabetically to avoid random order
Kubernetes-commit: f30c23a7831a25266a56b9b2990fa1ca19b48ad5
2025-04-27 15:36:09 +02:00
Jordan Liggitt 722397942b Drop null creationTimestamp from test fixtures
Kubernetes-commit: 6bb6c9934294d8265197c9dfc4c9dd3adaca147a
2025-03-24 09:37:26 -04:00
Jordan Liggitt 0cdb311ed6 bump cbor to add omitzero support
Kubernetes-commit: bc6051717137cef288b82305588e675de4a32c0d
2025-03-25 12:27:43 -04:00
Jordan Liggitt 4d172bd365 bump structured-merge-diff to add omitzero support
Kubernetes-commit: 06b0784062f68566daa8eed83c475b738dcf620c
2025-03-24 16:34:01 -04:00
Kubernetes Publisher 285ed6ce48 Merge pull request #131491 from tchap/kubectl-service-describe-trafficdistribution
kubectl describe service: Add Traffic Distribution

Kubernetes-commit: a19c0ad5533d1503825f22a3725de07cb81fced1
2025-04-28 12:05:03 +00:00
Ondra Kupka 4627533853 kubectl describe service: Add Traffic Distribution
Kubernetes-commit: ad40bc88568bdb19fdba0b960755bd014b2ae5e5
2025-04-26 18:02:19 +02:00
Rodrey ae92d5f0bd Add more test cases to TestDescribeSecret test (#131422)
* Converted to parameterised tests.

* Added test case for sorting with casing.

* Formatted code.

* Added test case for keys that contain numbers.

Kubernetes-commit: 74e84dbf5a339a3830ddd172fe8767ca0952cbb8
2025-04-24 20:10:05 +00:00
Kubernetes Publisher 3a0b77ee9b Merge pull request #131097 from ardaguclu/increase-cp-timeout
Increase kubectl cp command timeout to 30 seconds

Kubernetes-commit: 8237bc5035c7cdec4df561f56e9e68a4c26024f0
2025-04-24 00:26:44 +00:00
Kubernetes Publisher 9301b2a1f6 Merge pull request #130995 from xigang/utils
bump k8s.io/utils for improvements

Kubernetes-commit: 43a7d3be12425cc80ca6ad3599809a19728c5566
2025-04-24 00:26:43 +00:00
Kubernetes Publisher d40094d4e4 Merge pull request #130987 from arthurbdiniz/kubectl-diff-testing-language-env
Set LANGUAGE env variable in TestDiffProgram for consistent locale be…

Kubernetes-commit: da7f3cef166af40644ed9265d7a6a9d7a7e842d3
2025-04-24 00:26:42 +00:00
Taha Farahani 46f95a7c68 Unhandled panic crash on rollout_history printer.PrintObj (#130503)
* Change: Handling nil runtime.Object

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Return only if there is error in rollout_history

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Return the unknown revision error directly in rollout_history.go

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Remove unintended newline

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Using go idiomatic way for checking if historyInfo[o.Revision] exists

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Remove 'error:' from returned error message in rollout_history.go

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Check for printer.PrintObj returned err

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Add TestRolloutHistoryErrors test

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Simple typo fix on Complete() function description

Signed-off-by: Taha Farahani <tahacodes@proton.me>

* Change: Checking for error on o.Complete in TestRolloutHistoryErrors

Signed-off-by: Taha Farahani <tahacodes@proton.me>

---------

Signed-off-by: Taha Farahani <tahacodes@proton.me>

Kubernetes-commit: 609e4a9ba044e64a6244e053d2b1b7c545a2d2ed
2025-04-24 00:01:14 +03:30
Kubernetes Publisher b2ed890887 Merge pull request #130309 from HaraldNordgren/sort_secrets
kubectl: sort secrets alphabetically to avoid random order

Kubernetes-commit: 0130ac1422cf7e4af9d1ffd6c5fae24fe3eb320b
2025-04-24 00:26:40 +00:00
Kubernetes Publisher 265eadfda5 Merge pull request #127183 from mochizuki875/add_attach_warning
Add warning message for attach

Kubernetes-commit: d63a52a007da693cb40d2cfaef4f738cee104ab1
2025-04-24 00:26:39 +00:00
Harald Nordgren 6c0aa1995f pr fix
Kubernetes-commit: 4e3026fdb81667fd5a9fe928736b6e4d67b225e5
2025-04-14 15:59:45 +02:00
Kubernetes Publisher 72b3a7e9b0 Merge pull request #131204 from dims/move-to-released-version-of-prometheus/client_golang-v1.22.0-from-rc.0
Move to released version of prometheus/client_golang v1.22.0 from rc.0

Kubernetes-commit: 92af6ab6926f192a3d4543a1d6fa39f20edad3ea
2025-04-08 23:34:14 +00:00
Davanum Srinivas 2e566591a6 Move to released version of prometheus/client_golang v1.22.0 from rc.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 2ef4a8426c2c1b6e3495de08c4686382a752f8f7
2025-04-08 08:35:18 -04:00
Kubernetes Publisher fec9d5b3d5 Merge pull request #131103 from ahrtr/etcd_sdk_20250328
Bump etcd 3.5.21 sdk

Kubernetes-commit: f4d1686120d2367dd4c00df53e93dad51c414435
2025-04-01 11:49:33 +00:00
Benjamin Wang dc53668bca bump etcd 3.5.21 sdk
Signed-off-by: Benjamin Wang <benjamin.ahrtr@gmail.com>

Kubernetes-commit: f3b80a858225178e3f7a3ae07bd1b9894e7b3456
2025-03-28 14:30:47 +00:00
Arda Güçlü 399c585899 Increase kubectl cp command timeout to 30 seconds
Kubernetes-commit: 9c228e81d2481150878ca3a431f0ec9a8f150b3f
2025-03-28 12:39:01 +03:00
xigang ece3c8c1d0 bump k8s.io/utils
Kubernetes-commit: fe14689f221a968806b771b226581efb834654cd
2025-03-22 10:14:01 +08:00
Arthur Diniz 5b96de1a99 Set LANGUAGE env variable in TestDiffProgram for consistent locale behavior
Signed-off-by: Arthur Diniz <arthurbdiniz@gmail.com>

Kubernetes-commit: bad6c7e4cc5aef010c2fe2abfcbe51a138a04700
2025-03-21 17:28:41 +00:00
Kubernetes Publisher 5366de04e1 Merge pull request #129872 from seans3/websocket-https-proxy
WebSocket HTTPS Proxy support

Kubernetes-commit: 6f13ba03dac1865174b4edf2b43f6a0f453a8ac7
2025-03-21 09:25:21 +00:00
Kubernetes Publisher 7577f36fbc Merge pull request #130880 from tallclair/ippr-allocatable
[FG:InPlacePodVerticalScaling] Add back `AllocatedResources` and use it for scheduling

Kubernetes-commit: e87e840413aeb3e8ed899965480b3d86b49e4819
2025-03-20 06:23:20 +00:00
Tim Allclair f38b1de6c2 Consider AllocatableResources when computing pod requests
Kubernetes-commit: c2927727107cc8123c2688ea571f464650df6b2b
2025-03-17 21:23:32 -07:00
Kubernetes Publisher 0d5516dcdc Merge pull request #130033 from ardaguclu/completion-use-restclientgetter
Add completion in kubectl debug

Kubernetes-commit: 990b02bf3952a14249fe74add831a5bb02576995
2025-03-19 18:17:17 +00:00
Keita Mochizuki 5cbdedb625 kubectl debug: Display a warning message that the debug container's capabilities may not work with a non-root user (#127696)
* Add warning message about capabilities of debug container

* fix1

* fix2

* fix3

Kubernetes-commit: 07a275437f304456b2a32159ec6550a71d020a64
2025-03-19 10:15:57 +00:00
Kubernetes Publisher 6203603c4a Merge pull request #130906 from serathius/streaming-validation
Update kube-openapi and integrate streaming tags validation

Kubernetes-commit: 32b1819423de505da855cf7544e871a04e63d6ed
2025-03-19 06:29:44 +00:00
Marek Siarkowicz f97d1f5267 Update kube-openapi and integrate streaming tags validation
Kubernetes-commit: 75a4d136abac241f728407515e3d0d8305594675
2025-03-18 21:26:22 +01:00
Kubernetes Publisher 90ba96e4f3 Merge pull request #130733 from natasha41575/pod-resize-conditions
[FG:InPlacePodVerticalScaling] Move pod resize status to pod conditions

Kubernetes-commit: 473ec01548c81fc356308448dd47923d0f234612
2025-03-18 02:15:39 +00:00
Natasha Sarkar ed22800c0c Move pod resize status to pod conditions
Kubernetes-commit: a15520fbeaf458e2fc0f2be6e1ae0f9572369495
2025-03-17 22:01:05 +00:00
Kubernetes Publisher 920f676703 Merge pull request #130862 from icylord/kubectl
kubectl: Remove duplicate selector calculation logic and add missing test cases for the 'describe DaemonSet'

Kubernetes-commit: e950e517ed2547d4b870b7719fdda096373513ab
2025-03-17 22:16:12 +00:00
icylord 88b66ece35 kubectl: Remove duplicate selector calculation logic and add missing test cases for the 'describe DaemonSet' functionality
Kubernetes-commit: 3e48d143fa9d31bd690165109c79b413c67d5966
2025-03-15 17:07:44 +08:00
Kubernetes Publisher 5e1a193aef Merge pull request #130747 from soltysh/exec_context
kubectl: expose context parameter in DefaultRemoteExecutor

Kubernetes-commit: 6c3332e87071083afa234354516e720198840322
2025-03-12 22:16:32 +00:00
Maciej Szulik e4ccb76c1a kubectl: expose context parameter in DefaultRemoteExecutor
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 78e58b8c49fdcddba8cf939e5327440791c73a91
2025-03-12 15:51:13 +01:00
Kubernetes Publisher 277c37ab57 Merge pull request #130555 from thockin/k_k_randfill
Use randfill in k/k

Kubernetes-commit: 0f2bde7745f3b4eadcf317bc5056dfeb96859bd3
2025-03-09 14:32:21 +00:00
Tim Hockin 2bbe460b18 Vendor randfill
Kubernetes-commit: 0ce4268b1fe4f78d77249e329b0349b9d2dd2c65
2025-03-03 23:46:48 -08:00
Kubernetes Publisher f630fabade Merge pull request #130569 from dims/update-to-latest-cadvisor-v0.52.0
Update to latest cadvisor @ v0.52.1 and new opencontainer/cgroups and drops opencontainers/runc

Kubernetes-commit: 0eaee48ecb8669dc65bfdf9a3583326ab88fc39d
2025-03-08 02:29:24 +00:00
Davanum Srinivas a108757aa8 update to v1.22.0-rc.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 97a54dc4b04b7d2938d11c5ae9a6233348e854ef
2025-03-07 13:45:34 -05:00
Davanum Srinivas 8c173253d9 update to latest cadvisor @ v0.52.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 5ecddb65715af7e2afc4f3cbb1abe393bfb4346a
2025-03-04 14:29:08 -05:00
Kubernetes Publisher deef152435 Merge pull request #130349 from jpbetz/validation-gen-pr1
KEP-5073: Declarative Validation: Add validation generator

Kubernetes-commit: a5dda5d879cdae6562134ca7881ddf7f672f595d
2025-03-03 23:05:27 +00:00
Joe Betz cfdaf20447 Bump gengo/v2 to latest
Co-authored-by: Tim Hockin <thockin@google.com>
Co-authored-by: Aaron Prindle <aprindle@google.com>
Co-authored-by: Yongrui Lin <yongrlin@google.com>
# Conflicts:
#	vendor/modules.txt

Kubernetes-commit: 7f5e1baeeea7382e45cfba7676b69459fbce8b12
2025-03-03 09:49:50 -05:00
Kubernetes Publisher 8883001c90 Merge pull request #128919 from dashpole/update_otel
Update go.opentelemetry.io dependencies to v1.33.0/v0.58.0

Kubernetes-commit: eea2f78e61fe91bb8fcd3c4a357ea3a10d1389db
2025-03-02 00:57:26 +00:00
David Ashpole 24bba46b9d update go.opentelemetry.io dependencies to v1.33.0/v0.58.0
Kubernetes-commit: 29c219dcebe30be99d6917623f8d8707a47194c1
2025-03-01 19:17:16 +00:00
Kubernetes Publisher cab51f793f Merge pull request #130474 from dims/bump-x/crypto-and-x/oauth2
Bump x/oauth2 and x/crypto

Kubernetes-commit: 01ed8ed4ff0a0cbea99370c7a268019829d19e82
2025-02-28 21:00:52 +00:00
Kubernetes Publisher a9d88dcafc Merge pull request #129688 from cpanato/update-main-go124
[go] Bump images, dependencies and versions to go 1.24.0

Kubernetes-commit: b8c95e1954ef222988c0dfe5b45d5cc96c09bcb8
2025-02-27 21:03:20 +00:00
Davanum Srinivas 561b18e2ed Bump x/oauth2 and x/crypto
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 0fede7b8a2fb4c7f120876c9ef1e826f8ef28da2
2025-02-27 10:59:37 -05:00
cpanato 594231109f bump go.mod to set min go1.24
Signed-off-by: cpanato <ctadeu@gmail.com>

Kubernetes-commit: 88300c406b9199ed017e1bada29951fc18e66ae1
2025-02-25 13:21:52 +01:00
Kubernetes Publisher 1fe7110fa9 Merge pull request #130187 from mansikulkarni96/129084
fix:  Sweep and fix stat, lstat, evalsymlink usage for go1.23 on Windows

Kubernetes-commit: ef54ac803b712137871c1a1f8d635d50e69ffa6c
2025-02-23 00:42:24 +00:00
Harald Nordgren 3a69c59961 kubectl: sort secrets alphabetically to avoid random order
Kubernetes-commit: 7d6f86594fc0a7d09710c643de63b24cdcb98e65
2025-02-20 13:28:55 +01:00
Arda Güçlü 246e544fc4 Add completion in kubectl debug
Kubernetes-commit: 533a1211d30b42c4cb485468562e7712dc7f83c7
2025-02-07 13:44:21 +03:00
Jordan Liggitt ef54a58dd7 Drop winsymlink go 1.23 workaround
(cherry picked from commit 3990b6324d0427eaf9ff970da2be02711567ef5f)

Kubernetes-commit: 1f642c79c3192994e76bbe8e7360fd661cd21ab4
2025-02-06 12:45:52 -05:00
Kubernetes Publisher 71aa003817 Merge pull request #130298 from thockin/max_of_of
Fix dup word in API doc

Kubernetes-commit: f67b34612977b6efa7b8e7f37ef058ccef722373
2025-02-21 00:31:06 +00:00
Tim Hockin 4ccb6a52b9 Fix dup word in API doc
Kubernetes-commit: ec66befdcb2c2cf906e5321378ffd8edcccaeae6
2025-02-19 16:51:11 -08:00
Kubernetes Publisher 480491c908 Merge pull request #130249 from seans3/bump-websockets-version
Update gorilla/websockets library from 1.5.0 to latest 1.5.3

Kubernetes-commit: 728dc0d8c7a4d68157b2106330b65abcd5faac87
2025-02-19 04:47:21 +00:00
Kubernetes Publisher f6d73c948b Merge pull request #130238 from soltysh/subresource_stable
Update kubetl subresource to stable

Kubernetes-commit: 717d9f13f355539f2e8b58331e050e3155973db6
2025-02-19 04:47:20 +00:00
Sean Sullivan f1e93ac324 Update gorilla/websockets library from 1.5.0 to latest 1.5.3
Kubernetes-commit: 3100bbab2f7f013b08910f28d8a3debc28a57ea9
2025-02-19 00:26:21 +00:00
Maciej Szulik 7f2f474232 Update kubetl subresource to stable
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: de984ec9b92bcf6ff17060b1cdecdd8fd948bcbb
2025-02-18 14:28:59 +01:00
Arda Güçlü 2e38fc2204 Introduce kuberc as new flag to customize defaulting and define aliases in kubectl (#125230)
Kubernetes-commit: c7a90b670c40a315bea3667921302675008bc39c
2025-02-12 00:39:09 +00:00
Kubernetes Publisher 2fd8e3617a Merge pull request #128367 from vivzbansal/sidecar-2
[FG:InPlacePodVerticalScaling] Implement resize for sidecar containers

Kubernetes-commit: 0634e21fb525743e68d677c53753b43a8b7471bc
2025-02-06 01:32:49 +00:00
Sean Sullivan 313e838cfa Websocket HTTPS proxy support
Kubernetes-commit: f73945aae56b51078318199ff2f0ecae91bc489e
2025-01-29 03:56:55 +00:00
vivzbansal 79fb20cb8b Resolved latest review comments
Kubernetes-commit: 5889da1bbc7a3e515bf6e3d5ca35d600020ff046
2024-12-17 07:56:13 +00:00
Kubernetes Publisher 316ed014ab Merge pull request #129784 from soltysh/refactor_explain
Refactors explain command to split flags from options

Kubernetes-commit: f6f06806cc43ed9f7eb2f68368c90a8239884118
2025-01-24 09:08:18 +00:00
Maciej Szulik d74f0e1af1 Switch from using a function to just pure map in create token
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 87139335b0e6ce5f5bc08d860a870fb9f16392b2
2025-01-23 13:10:06 +01:00
Maciej Szulik 1ab40ed1c8 Finish extracting ExplainFlags structure
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 3030b1dc6a445929c20dc911196746c2d8af2bac
2025-01-23 13:09:19 +01:00
mochizuki875 81562142de Add warning message for attach
Kubernetes-commit: 97dd6dc284682d76fe7e0bc51df851473deee24f
2024-09-06 02:31:14 +00:00
PuneetPunamiya bcafb59748 Refactors explain command to split flags from options
Signed-off-by: Puneet Punamiya ppunamiy@redhat.com
Signed-off-by: Maciej Szulik <soltysh@gmail.com>

Kubernetes-commit: 91afef615ad918cfc364bf5e6d12a96785f2acaf
2022-10-20 12:48:15 +05:30
Kubernetes Publisher 8af785f4be Merge pull request #128971 from aojea/servicecidr_ga
KEP-1880 Multiple Service CIDRs: Graduate to GA

Kubernetes-commit: 45d0fddaf1f24f7b559eb936308ce2aeb9871850
2025-01-22 21:59:57 +00:00
Antonio Ojea 064a840924 describe servicecidr and ipaddress v1
Kubernetes-commit: e3b39758215f152fe59e94b86d1c6db3320103f5
2024-11-26 03:35:16 +00:00
Kubernetes Publisher 7346aee2d4 Merge pull request #129633 from skitt/revert-go-difflib-go-spew
Revert to go-difflib and go-spew releases

Kubernetes-commit: 6d570c923f66a1f214d0c3ba3eddd9a0cd0fae68
2025-01-15 21:23:05 +00:00
Stephen Kitt d384e79d1a Revert to go-difflib and go-spew releases
The last dependency pulling in the tips of go-difflib and go-spew has
reverted to the last release of both projects, so k/k can revert to
the releases too. As can be seen from the contents of vendor, this
doesn't result in any actual change in the code.

Signed-off-by: Stephen Kitt <skitt@redhat.com>

Kubernetes-commit: 3986472b3c7202716f92e586ccfaa4b4fe573dc5
2025-01-15 09:07:27 +01:00
Kubernetes Publisher 7d49790b11 Merge pull request #129622 from dims/update-to-latest-kustomize-v5.6.0
Update to latest kustomize v5.6.0 to drop `github.com/asaskevich/govalidator`

Kubernetes-commit: 42811635adc4840a6769d7a9f7fd47be8df99c43
2025-01-15 01:11:12 +00:00
Davanum Srinivas 7f667b45ca Update to latest kustomize/v5.6.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 0d8a8fe3065d6bbff623eeb70dc86b6085fd4c3c
2025-01-14 13:10:47 -05:00
Kubernetes Publisher cee2a595e4 Merge pull request #129349 from dims/bump-x/net-to-v0.33.0
Bump x/net to v0.33.0

Kubernetes-commit: b7ef173c59065f9a5f68eb514ef0483c6f3887ae
2025-01-06 21:18:31 +00:00
gshaibi 3e68cbc2c4 [kubectl] Enhance describe output for projected volume sources to indicate optional Secret/ConfigMap (#129457)
* kubectl: enhance output for projected volume sources to indicate optional secrets

* .

Kubernetes-commit: 4114a9b4e45a4df96f0383d87b2649640a6ffbf1
2025-01-06 15:50:16 +02:00
Kubernetes Publisher 6990be915a Merge pull request #128872 from alvaroaleman/generics
Use generic btree in watchcache

Kubernetes-commit: 8f8c94a04d00e59d286fe4387197bc62c6a4f374
2025-01-03 17:17:34 +00:00
Alvaro Aleman 1613733931 Update github.com/google/btree
Kubernetes-commit: a97ed3c98bcd2c520260aa04c516a24e975e7d69
2025-01-02 19:44:07 -05:00
lixiv be364695f5 Add tests for kubectl qos (#129388)
* Add tests for kubectl qos

* Update staging/src/k8s.io/kubectl/pkg/util/qos/qos_test.go

Co-authored-by: Arda Güçlü <aguclu@redhat.com>

---------

Co-authored-by: Arda Güçlü <aguclu@redhat.com>

Kubernetes-commit: 215d0b094b686ae0ad83a8f2d3078e5860a979ba
2024-12-30 09:06:10 +00:00
Davanum Srinivas ddd9a046e7 Bump x/net to v0.33.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 0b6e3718340fa7e3846cf9b7d5a0f7a684a6fa5a
2024-12-20 14:30:57 -05:00
Kubernetes Publisher a8a00dbee1 Merge pull request #128950 from googs1025/feature/kubectl/autoscalev2
feature(kubectl): use autoscalingv2 in kubectl autoscale

Kubernetes-commit: fc53d1b297e8b393855b06b993f1e712a24883b7
2024-12-18 18:38:55 +00:00
Omer Aplatony 120105a0a9 kubectl: add test coverage for cordon command (#129202)
* kubectl: add test coverage for cordon command

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* using cmp.Diff

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

---------

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: 3ec97a445f036a38bfec6291dee661954138bac9
2024-12-17 06:34:43 +00:00
Kubernetes Publisher 088003e485 Merge pull request #129213 from Jefftree/k-openapi
Bump kube-openapi

Kubernetes-commit: 13eb074ddd231d127709f0410185eeca68a69c8a
2024-12-14 02:45:48 +00:00
Jefftree 816d854fc8 bump kube-openapi
Kubernetes-commit: 3269f4bb94c58dfe577621c42f88ea06fbdd79a7
2024-12-13 20:50:49 +00:00
Kubernetes Publisher 1a5fd321ec Merge pull request #129195 from dims/update-x/crypto/ssh-dependency
Update x/crypto/ssh dependency to v0.31.0

Kubernetes-commit: b21ab179c74a270cd276d2dbb5f4b55730838096
2024-12-13 10:46:53 +00:00
Davanum Srinivas 575c21a9f0 Update x/crypto/ssh dependency
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 80735180ab2c61232dcc4646e693ddcaeaf96ca3
2024-12-12 20:46:15 -05:00
Kubernetes Publisher 94246703f3 Merge pull request #129054 from pohly/remove-import-name
remove import doc comments

Kubernetes-commit: e8615e27125518f0ed0ba06244b7ecee21451bb0
2024-12-12 10:41:15 +00:00
Kubernetes Publisher 74629f681a Merge pull request #129106 from rotsix/patch-1
docs: `-l/--selector` example for set-based requirements

Kubernetes-commit: d1b702b0b83b7c4ea8d06b2dbd9d33e337117b9d
2024-12-12 10:41:13 +00:00
Kubernetes Publisher 86048014d6 Merge pull request #128909 from ardaguclu/kubectl-set-generic
Use generic sets rather than deprecated sets.String

Kubernetes-commit: 5bfdd18f0b3a1820e2ca0242ef8668532c175fb7
2024-12-12 06:49:47 +00:00
Omer Aplatony 56c9d286fe kubectl: fix wait --for=create to work correctly with label selectors (#128662)
* kubectl: fix wait --for=create to work correctly with label selectors

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* Add unit test

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* add integration test

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* Increase wait time to 40 seconds

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

---------

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: 0cc926220067cd814cecd8f3d0c3b9235e6a68db
2024-12-12 06:49:46 +00:00
alingse 92bb3cdeda fix: fix miss makezero bug (#125132)
* fix: fix miss makezero bug

Signed-off-by: alingse <alingse@foxmail.com>

* add testcase for new verb

* Update create_role_test.go

---------

Signed-off-by: alingse <alingse@foxmail.com>

Kubernetes-commit: 5b06498cb24ee68dbc2815a1d9fa505da3452d98
2024-12-12 10:56:37 +08:00
Kubernetes Publisher beeec3d7a0 Merge pull request #129103 from liggitt/drop-winreadlinkvolume
Drop use of winreadlinkvolume godebug option

Kubernetes-commit: bfe431b53e600c9a36c46eef0f6ecfcf37265d60
2024-12-06 20:00:07 +00:00
Victor Franzi 40fde549ca docs: `-l/--selector` example for set-based requirements
add an example of set-based requirement when using `-l/--selector` as it's a (less known) filtering capability: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering

Kubernetes-commit: 8f48a82e6ed9fd19601ad8c32a5f1b55b4299fb0
2024-12-06 12:03:48 +01:00
Jordan Liggitt ee2ac712ef Drop use of winreadlinkvolume godebug option
Kubernetes-commit: 3046fe23d4fe4ba86713ffd61bf0e07156b2b7c3
2024-12-06 02:40:53 -05:00
Kubernetes Publisher e26c49a5f9 Merge pull request #129083 from liggitt/go1.23windows
Revert to go1.22 windows filesystem stdlib behavior

Kubernetes-commit: 6fc64a261c1dca857a5a7fd1bc87fae38dbe1c8a
2024-12-04 23:19:21 +00:00
Jordan Liggitt 9f75b795dc Revert to go1.22 windows filesystem stdlib behavior
Kubernetes-commit: 3878a3a6de64660e356a35f70471c27a09698090
2024-12-04 09:52:56 -05:00
Patrick Ohly 348f12d905 remove import doc comments
The "// import <path>" comment has been superseded by Go modules.
We don't have to remove them, but doing so has some advantages:

- They are used inconsistently, which is confusing.
- We can then also remove the (currently broken) hack/update-vanity-imports.sh.
- Last but not least, it would be a first step towards avoiding the k8s.io domain.

This commit was generated with
   sed -i -e 's;^package \(.*\) // import.*;package \1;' $(git grep -l '^package.*// import' | grep -v 'vendor/')

Everything was included, except for
   package labels // import k8s.io/kubernetes/pkg/util/labels
because that package is marked as "read-only".

Kubernetes-commit: 8a908e0c0bd96a3455edf7e3b5f5af90564e65b0
2024-12-02 14:43:58 +01:00
Arda Güçlü 61dc2ecb38 Use generic Contains rather than deprecated ContainsString
Kubernetes-commit: 8312c3ec242faf30f3967e59465ca5a764a4ee85
2024-11-25 11:30:04 +03:00
googs1025 e2968fb8ad feature(kubectl): use autoscalingv2 in kubectl autoscale
Kubernetes-commit: a87dd67a3c89612828d613cd71828a906b4d7c3c
2024-11-23 21:43:29 +08:00
Arda Güçlü 608a0553d7 Use generic sets rather than deprecated sets.String
Kubernetes-commit: c3f15fd707a092e6cb7d96b84b81ada1f118d759
2024-11-21 13:22:39 +03:00
Kubernetes Publisher 169a952417 Merge pull request #128559 from lauralorenz/crashloopbackoff-refactorimagepullbackoff-e2enodecriproxytest
E2E Node tests for image pull backoff and crashloopbackoff behavior

Kubernetes-commit: 5ee686b6cfd1431dbde77873f64d9c2a90610745
2024-11-13 20:25:58 +00:00
Kubernetes Publisher d0bc9691f3 Merge pull request #128761 from ah8ad3/revert-126533
Revert PR #126533 and add a test case for broken case

Kubernetes-commit: af7581e8ec6839c0eb7405cdd95af3285434cdcb
2024-11-13 06:05:42 +00:00
Laura Lorenz 133d258d8e Use a better util
Signed-off-by: Laura Lorenz <lauralorenz@google.com>

Kubernetes-commit: 8e7b2af712a79db423b7bfdf2a7bf35f75542c13
2024-11-12 23:26:04 +00:00
Laura Lorenz 1811ebafa9 Clearer image pull test and utils
Signed-off-by: Laura Lorenz <lauralorenz@google.com>

Kubernetes-commit: 285d433dea79e6838cdd0648c36a2a82fd398179
2024-11-12 22:48:17 +00:00
ah8ad3 7ff7f80add Revert PR #126533 and add a test case for the case where there is yaml
structed texts in the description.
We should find a way to both relign line breaks and not break these kind
of texts.

Signed-off-by: ah8ad3 <ah8ad3@gmail.com>

Kubernetes-commit: 7580e6ac00b00cf6e7ba375a3730e0dccbf40463
2024-11-12 14:23:03 +03:30
Kubernetes Publisher 6e4fe32a45 Merge pull request #128407 from ndixita/pod-level-resources
[PodLevelResources] Pod Level Resources Feature Alpha

Kubernetes-commit: c25f5eefe4efda4c0d9561d06942cd3de3dfe2e4
2024-11-08 16:13:12 +00:00
ndixita 9a565d149e QOS changes for Pod Level resources
Kubernetes-commit: 26f11c458620751733250b35d1f60c9ed2a96e57
2024-10-30 01:24:36 +00:00
ndixita 1f9df3421a Adding support for pod level resources in kubectl
1. Add support for pod level resources in kubectl
2. Reuse the existing method to describe container resources and generalize it to describe both pod and container level resources

Kubernetes-commit: 502e0f55c43291af800e8633760d461343bd39b3
2024-10-24 21:13:54 +00:00
Omer Aplatony 2bb31e1a0f Replace PollImmediate with PollUntilContextTimeout (#128147)
* Replace PollImmediate with PollUntilContextTimeout

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* Add context to RetryErrorCondition function

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* lint: fix error comparison in scale package

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* Fix RetryErrorCondition function signature

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

* revert to if err statement

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

---------

Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: 9d816f1587c918e7acae6d9195d33606aec998b1
2024-11-07 16:57:29 +02:00
Kubernetes Publisher 2cccb2df6a Merge pull request #124952 from AxeZhan/maxContainerRestarts
[Sidecar Containers] Pods comparison by maxContainerRestarts should account for sidecar containers

Kubernetes-commit: 9a9331afd60a4db3ffd8dc9bd38b788948308175
2024-11-08 16:13:08 +00:00
Kubernetes Publisher 4ced6667a4 Merge pull request #128593 from jpbetz/bump-cel-123
Introduce CEL two variable comprehensions

Kubernetes-commit: dc01fa9d2b6632dc932eb760573659608add1b8f
2024-11-07 04:01:54 +00:00
Joe Betz b7988e1775 hack/pin-dependency.sh github.com/google/cel-go v0.22.0
Kubernetes-commit: b0180a9a376caee4a12cbf549b3187d21cbdc07d
2024-11-05 19:21:09 -05:00
Kubernetes Publisher 2ebf801b89 Merge pull request #128296 from AnishShah/kubectl-resize
[FG:InPlacePodVerticalScaling] Remove restrictions on subresource flag in kubectl commands

Kubernetes-commit: f451aec23787c2b48489eea2377cd13dfa15bded
2024-11-06 11:56:50 +00:00
Anish Shah b22c40d47c kubectl: remove subresource restrictions from all commands
Removing this restrictions will allow us to use these commands with the
new resize subresource.

Kubernetes-commit: e1ca63489f2b788f893ab37a27242ce319e1eaf6
2024-10-31 16:00:52 -07:00
Kubernetes Publisher 4b9836ac7a Merge pull request #128377 from tallclair/allocated-status-2
[FG:InPlacePodVerticalScaling] Implement AllocatedResources status changes for Beta

Kubernetes-commit: f81a68f4888c9da87f856d17516fb810518a67c0
2024-11-06 03:55:35 +00:00
Kubernetes Publisher 913dcdf388 Merge pull request #128580 from jpbetz/bump-kube-openapi
Bump kube-openapi to latest

Kubernetes-commit: 9a2a7537f035969a68e432b4cc276dbce8ce1735
2024-11-06 00:01:11 +00:00
Kubernetes Publisher e91a2f1400 Merge pull request #126533 from ah8ad3/kubectl-explain-wrap
Realign line breaks in kubectl explain wrap method

Kubernetes-commit: 602c70b65d49e0687026064edb8601087da00bd2
2024-11-05 19:56:24 +00:00
Kubernetes Publisher 2fceb953a8 Merge pull request #128352 from omerap12/fix-empty-remote-port
port-forward: fixed error handling for empty remote port

Kubernetes-commit: 033b275d109a662119ac745262ef7a9b4607a0a8
2024-11-05 15:49:36 +00:00
Joe Betz dc24746c3a hack/pin-dependency.sh k8s.io/kube-openapi 32ad38e42d3faf1ce94eb29f4ea6d763339b258e
Kubernetes-commit: f2157ff73e3c9b7c2a36bf371e388e8976d93975
2024-11-05 10:18:57 -05:00
Kubernetes Publisher 6989e5df8d Merge pull request #128396 from ritazh/deprecate-EnforceMountableSecretsAnnotation
deprecate EnforceMountableSecretsAnnotation in 1.32

Kubernetes-commit: bc79d3ba87b8b3c4b7c68f26cdfcaa35654d96ac
2024-11-05 07:56:14 +00:00
Rita Zhang 739aca7b89 deprecate EnforceMountableSecretsAnnotation in 1.32
Signed-off-by: Rita Zhang <rita.z.zhang@gmail.com>

Kubernetes-commit: e7cdc595551954d6b87a859296eb09fddd01f3c9
2024-10-28 08:01:33 -07:00
Kubernetes Publisher 7ec5989b2d Merge pull request #128507 from dims/use-k8s.io/utils/lru-instead-of-github.com/golang/groupcache/lru
Use k8s.io/utils/lru instead of github.com/golang/groupcache/lru

Kubernetes-commit: 7a4d755644e83dfade7bbc4c240c204a9e54d9c0
2024-11-05 00:02:15 +00:00
Davanum Srinivas c5abf9ddc7 Use k8s.io/utils/lru instead of github.com/golang/groupcache/lru
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 2b0592ee77d0a0bb3017df042066ecb8c83d2fb3
2024-11-01 22:19:11 -04:00
Kubernetes Publisher a886863a93 Merge pull request #128494 from dims/drop-go-colortext-and-its-usage
Drop go-colortext and its usage

Kubernetes-commit: 6ae2d359ad2eed549f467016465d04fa4b222b7a
2024-11-04 15:50:43 +00:00
Kubernetes Publisher 4532c53760 Merge pull request #128470 from omerap12/autoscale-unit
kubectl: add test coverage for autoscale command

Kubernetes-commit: f4d05aad776f6439de578497bb5076b512f907ad
2024-11-04 11:50:30 +00:00
Kubernetes Publisher 3cd67e0222 Merge pull request #128481 from carlory/dependencies-ginkgo-gomega
dependencies: ginkgo v2.21.0, gomega v1.35.1

Kubernetes-commit: 88a997ac01cd8a386df9318d81b89257307f53fb
2024-11-01 20:01:53 +00:00
Davanum Srinivas 69f03b081e Drop go-colortext and its usage
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: d450b6e653a8dcf11f28822eadea379734b3f53d
2024-11-01 09:55:42 -04:00
carlory b67296a41b dependencies: ginkgo v2.21.0, gomega v1.35.1
Kubernetes-commit: 80b1a297865500891bd823005ace761becae5dbf
2024-11-01 11:35:24 +08:00
Kubernetes Publisher 3553001de4 Merge pull request #128416 from jpbetz/reset-filter
Add optional ResetFieldsFilterStrategy interface for storage

Kubernetes-commit: b831df733e5cf244331f61fffb0ba86787b27236
2024-11-01 05:41:11 +00:00
Joe Betz c7e911a6b5 hack/pin-dependency.sh sigs.k8s.io/structured-merge-diff/v4 v4.4.2
Kubernetes-commit: 6fe51403665f1b6e820226004817b92e3118cabc
2024-10-31 21:19:15 -04:00
Omer Aplatony bb485d40d9 kubectl: add test coverage for autoscale command
Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: 6cb17d85a550ce8237f8542a9e59fdd03973c7d6
2024-10-31 14:26:15 +02:00
Omer Aplatony dc6975b78c port-forward: fixed error handling for empty remote port
Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: c01a8a51af10811e182be896795168bbd561c7e9
2024-10-26 14:24:09 +03:00
Tim Allclair af49e676b2 Stop using status.AllocatedResources to aggregate resources
Kubernetes-commit: 81df1958196e04f04d038e5ec9e2025989a30b29
2024-10-25 21:18:19 -07:00
Kubernetes Publisher a499023358 Merge pull request #125314 from enj/enj/i/proto_for_core
Use protobuf for core clients

Kubernetes-commit: 7b7a7968d4c90c4430b1009546e13ce78bcde134
2024-10-24 18:55:48 +00:00
Monis Khan 1014b1d5f2 Fix tests that assume core clients use JSON
Signed-off-by: Monis Khan <mok@microsoft.com>

Kubernetes-commit: 6595fa40268bc8e7f46dcc28267e5e8b0b1ae493
2024-08-19 10:38:16 -04:00
Kubernetes Publisher 816c382177 Merge pull request #122818 from y1hao/fix-typo
Fix error in i18n package usage examples

Kubernetes-commit: e6659b60f88575d4c1037d0de41292aa3aba010f
2024-10-23 02:53:32 +00:00
Arda Güçlü 4c8c153513 Wire context to logs command and add interrupt handler (#127503)
* Wire context to logs command and add interrupt handler

* Move conditional outside of interrupt handler

Kubernetes-commit: 5826868586d501060a6151d04c511236b11a26d4
2024-10-22 21:49:06 +03:00
Arda Güçlü 484ede079f KEP-4292: Add e2e test for custom profile in kubectl debug (#127187)
* Remove KUBECTL_DEBUG_CUSTOM_PROFILE env var

* Add e2e test for custom profile in kubectl debug

* Keep feature flag until 1.33

* Update comment

* Simplify tests by relying on test framework functionality

* Rename import alias to better to pass verify-import-alias

Kubernetes-commit: 1caf9a150b794a7c4a17e63a54b902ec0b0be570
2024-10-22 21:48:59 +03:00
Kubernetes Publisher 73f8c2980c Merge pull request #128165 from liggitt/prune-self-require
Drop self-referencing replace directives

Kubernetes-commit: a8fc7ae761c19ab436cf513c9eed877f08961cf7
2024-10-18 05:25:58 +00:00
Jordan Liggitt 87fbd1d830 Drop self-referencing replace directives
Kubernetes-commit: 3be1109829d4b0921972bb8b5f66a4d179ff6255
2024-10-17 15:51:15 -04:00
Kubernetes Publisher f829c4b789 Merge pull request #128064 from dims/update-to-last-versions-of-some-very-infrequently-updated-repos
Update to last versions of some very infrequently updated repos

Kubernetes-commit: 07e73682b9a5259cacac978346ed4567588e4165
2024-10-16 06:55:24 +00:00
Kubernetes Publisher 1b29da9296 Merge pull request #128081 from soltysh/strict_spacing
Fix spacing in --validate flag description

Kubernetes-commit: 99cc395e2b9870ab9813e7ea4c0940225e30d05d
2024-10-15 12:24:28 +01:00
Maciej Szulik 80dc149179 Fix spacing in --validate flag description
Kubernetes-commit: 7b0660ec9f572c7b8c964c5447aa9169684f9a2b
2024-10-15 11:16:33 +02:00
Davanum Srinivas 84e8e731c9 Update to last versions of some very infrequently updated repos
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 7f8210e33f8cd626d1fb86cd7d12d077ec3047d5
2024-10-14 17:23:16 -04:00
Kubernetes Publisher c1f9faf7c3 Merge pull request #128051 from googs1025/kubectl/fix/resourcebuilder
bug(kubectl): return resource builder error in scale cmd

Kubernetes-commit: 9a0b07d38cb95d0d55044e591839c131a9258e2f
2024-10-14 18:47:38 +00:00
googs1025 c90e4a0fd8 bug(kubectl): return resource builder error in scale cmd
Kubernetes-commit: 8d084809296a845f01a0a1177bb0bf825f498d84
2024-10-14 18:25:13 +08:00
Kubernetes Publisher 86e0d9e48c Merge pull request #127881 from omerap12/drain-package-PollUntilContextTimeout
Update waitForDelete to use PollUntilContextTimeout

Kubernetes-commit: 5b1a4caedae0ca28adc2b22837789d6828b74d19
2024-10-14 06:41:57 +00:00
Kubernetes Publisher 3aac470db0 Merge pull request #127998 from skitt/golang-x-oct-2024
October 2024 golang.org/x bump

Kubernetes-commit: 8cbb11519c54c120e2dc120a4799e53abbfea4a4
2024-10-11 15:32:13 +00:00
Kubernetes Publisher 1d2b08a308 Merge pull request #127985 from dims/update-moby-runc-dependencies-oct-10
Update moby/runc dependencies

Kubernetes-commit: 6e5e8f374e834fa8dab341bde5c522704ed55ba6
2024-10-11 15:32:11 +00:00
Stephen Kitt 55b0096f22 October 2024 golang.org/x bump
Nothing major here, but nothing liable to cause pain to downstreams
either.

* https://github.com/golang/crypto/compare/v0.26.0...v0.28.0 (there’s
  a SHA3 fix there but it’s only relevant for 32-bit platforms)
* https://github.com/golang/net/compare/v0.28.0...v0.30.0 (mostly
  http2; route address parsing fix on Darwin)
* https://github.com/golang/oauth2/compare/v0.21.0...v0.23.0 (Google
  license fix)
* https://github.com/golang/sys/compare/v0.23.0...v0.26.0 (faster
  getrandom() on Linux through the vDSO; improved RISC-V support)
* https://github.com/golang/term/compare/v0.23.0...v0.25.0
* https://github.com/golang/time/compare/v0.3.0...v0.7.0 (0-limit
  handling fix in x/time/rate; Google license fix)
* https://github.com/golang/tools/compare/v0.24.0...v0.26.0

This doesn’t include golang.org/x/exp; that doesn’t have any relevant
changes. There’s an apidiff fix but we always pull in the latest
apidiff anyway.

Signed-off-by: Stephen Kitt <skitt@redhat.com>

Kubernetes-commit: 6c5a528727c30803d4426b29c06ae5d350619877
2024-10-11 10:22:13 +02:00
Davanum Srinivas fb82836788 Update moby/runc dependencies
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 521f2d106b9c5744ce57a8ec03124bcdadbca986
2024-10-10 11:58:22 -04:00
Kubernetes Publisher 9e16ef8eda Merge pull request #127942 from liggitt/json123
sigs.k8s.io/json go 1.23 bump

Kubernetes-commit: fc318e3ba4cb1db822d7f802993059846f64179d
2024-10-10 22:55:53 +00:00
Jordan Liggitt fa1f5fc526 Update sigs.k8s.io/json to go1.23
Kubernetes-commit: 8eff759b6ac7c3bb0c6a8823c751f5a578d6f721
2024-10-10 11:00:11 -04:00
Kubernetes Publisher a0488cfbe5 Merge pull request #127869 from ak20102763/explain_o_shorthand
Added shorthand for kubectl explain --output

Kubernetes-commit: 1f9d2577da68290c0466c1404bbff6100e1e303a
2024-10-10 10:42:41 +00:00
Kubernetes Publisher 184746c687 Merge pull request #127965 from koba1t/dependencies/update_kustomize_v5.5.0
Update kubectl kustomize to v5.5.0

Kubernetes-commit: e7bc45269d53da81d276efdde06dcbbeb4c286cc
2024-10-10 02:43:59 +00:00
Kubernetes Publisher 7ed2361d8a Merge pull request #127901 from skitt/k8s-sigs-yaml
Use sigs.k8s.io/yaml instead of gopkg.in/yaml

Kubernetes-commit: dd87bc064631354885193fc1a97d0e7b603e77b4
2024-10-09 23:29:02 +00:00
koba1t 983dddad9d Update kubectl kustomize to kyaml/v0.18.1, cmd/config/v0.15.0, api/v0.18.0, kustomize/v5.5.0
Kubernetes-commit: e7daa708520502cb375945af117b9e647acf5014
2024-10-09 23:32:45 +09:00
Kubernetes Publisher 2bb291358c Merge pull request #125118 from jsoref/from-to
Order ScalingReplicaSet message from->to

Kubernetes-commit: a1df68a31f535d4d4d55090e89805d8e574c3aa9
2024-10-09 10:46:02 +00:00
Kubernetes Publisher 7c89fa5dca Merge pull request #126932 from zhifei92/kubectl-describe-ep
Fix the bug where "kubectl describe svc' endpoints"behaves unexpectedly.

Kubernetes-commit: c270e562525a84e496cdbbb1ab7ced31bd2eeaca
2024-10-09 10:46:01 +00:00
Stephen Kitt 0f462824c7 Use sigs.k8s.io/yaml instead of gopkg.in/yaml
Since we have a Kubernetes-specific fork of go-yaml, use that
consistently throughout the project. This doesn't eliminate the
dependencies on gopkg.in/yaml, which are still used indirectly; but it
ensures that the whole project benefits from fixes or changes to
sigs.k8s.io/yaml.

Signed-off-by: Stephen Kitt <skitt@redhat.com>

Kubernetes-commit: f1fa4086b329376861272708d81da7988e8c4ad0
2024-10-07 14:27:52 +02:00
Omer Aplatony c329ccff7c Update waitForDelete to use PollUntilContextTimeout
Signed-off-by: Omer Aplatony <omerap12@gmail.com>

Kubernetes-commit: bba055067e6283f94ee05cedeb33dacafe4a1094
2024-10-05 22:07:37 +03:00
Akash 4106fc8791 Added shorthand for explain --output
Removed short flag example

Kubernetes-commit: 923a41370dc85062241fa149edda1307a16910e2
2024-10-05 03:19:57 +05:30
zhifei92 f3a7f811d0 fix: kubeclt describe service endpoints shows endpoints that are not ready
Kubernetes-commit: 64e2066e5c823eaa958fcbdd6024d0253688f36c
2024-08-27 12:42:37 +08:00
Kubernetes Publisher 5f5894cd61 Merge pull request #127634 from deads2k/apply-subresource
add --subresource to kubectl apply

Kubernetes-commit: bb6bfba47510c699cbbd1e910f37caca4c634359
2024-10-03 02:38:35 +00:00
Kubernetes Publisher 867c9194ad Merge pull request #127685 from mmorel-35/testifylint/expected-actual@k8s.io/kubectl
fix: enable expected-actual rule from testifylint in module `k8s.io/kubectl`

Kubernetes-commit: 1b4024948878fd8aab19deff48ae8b7102f0d34a
2024-09-29 09:22:35 +00:00
Kubernetes Publisher 4315ad9aaa Merge pull request #126764 from liggitt/mergo
reimplement merge to drop mergo dependency

Kubernetes-commit: ee74baec6e05afde972f1a8705d4f8efe066f120
2024-09-28 09:22:50 +00:00
Matthieu MOREL 36d3a02b4d fix: enable expected-actual rule from testifylint in module `k8s.io/kubectl`
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>

Kubernetes-commit: 223ea3445c2ced92630732ca765dee56bccae8ed
2024-09-27 07:47:42 +02:00
David Eads d6ad8b12b7 add --subresource to kubectl apply
Kubernetes-commit: 55ba8b2cbb375aaedcd01dd5d4dd0f81ef0415bf
2024-09-25 17:23:09 -04:00
Jordan Liggitt 4d5b682af1 Update vendor
Kubernetes-commit: 745ae75a15cad2f1c5da5518c00f2eb366ffb786
2024-08-17 21:42:00 -04:00
Kubernetes Publisher 5d2e9155d4 Merge pull request #127646 from mmorel-35/testifylint/formatter@k8s.io/kubectl
fix: enable formatter rule from testifylint in module `k8s.io/kubectl`

Kubernetes-commit: 4b33029691adceaa83bbd8e9879b5a6b455634e1
2024-09-26 13:12:30 +00:00
ah8ad3 e4a11c9548 realign line breaks in kubectl exaplin wrap method
Kubernetes-commit: 008f17419a0decbb82985a74a730a8b60ed07e5d
2024-08-04 10:02:17 +03:30
Matthieu MOREL c0e80201dc fix: enable formatter rule from testifylint in module `k8s.io/kubectl`
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>

Kubernetes-commit: 3e558fe604d9f209a9758e30866226aefda39f8a
2024-07-14 07:58:03 +00:00
Kubernetes Publisher 6c52e7fa5d Merge pull request #127512 from bergerhoffer/adding-interactive-delete
Adding example for interactive delete

Kubernetes-commit: 257d6f3f5bf75ff0ce6c53c104a0ab9df1ed5059
2024-09-23 09:07:30 +00:00
Kubernetes Publisher bbfe64c1ac Merge pull request #127534 from mmorel-35/testifylint/contains@k8s.io/kubectl
fix: enable contains rule from testifylint in module `k8s.io/kubectl`

Kubernetes-commit: 25aa9cd074072307a1168259c92cfefb1eafc27a
2024-09-23 09:07:29 +00:00
Kubernetes Publisher f92e952318 Merge pull request #126799 from kiashok/update-cadvisor-hcsshim
Update cadvisor and hcsshim versions

Kubernetes-commit: 4c2e23904794a289be22b2c9bce3303edfa0f622
2024-09-23 05:15:52 +00:00
Matthieu MOREL cfb4ff091f fix: enable contains rule from testifylint in module `k8s.io/kubectl`
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>

Kubernetes-commit: 1e7bd5541ea20b41d961f1bb88d9cc958a69ff66
2024-09-22 11:56:01 +02:00
Andrea Hoffer a0d920bb63 Adding example for interactive delete
Kubernetes-commit: 8e7593e18ab1788dc15e7f7db669301adcd42b2e
2024-09-20 14:54:52 -04:00
Kirtana Ashok 20877bc489 Update cadvisor and hcsshim versions
Signed-off-by: Kirtana Ashok <kiashok@microsoft.com>

Kubernetes-commit: 3fba9930b72f78b53fb83b0d533a426080c0f92e
2024-09-05 08:35:53 -07:00
Kubernetes Publisher 5e52c27b4e Merge pull request #127422 from srivastav-abhishek/go-vet-fix
Go vet fixes for gotip

Kubernetes-commit: f2700895a4315014c56bfe1db7fb1562a61a8b50
2024-09-20 17:20:59 +00:00
Keita Mochizuki 90452b2e92 kubectl debug: warning message about legacy profile (#127230)
* Add warning message for legacy profile

* fix1

* fix2

Kubernetes-commit: dd4943c831dbc43fb8d410ccdbc27e3c807131fa
2024-09-20 00:28:38 +09:00
Kubernetes Publisher 650e81b1f2 Merge pull request #126588 from jingyuanliang/master
kubectl/describe: use function calls to build field selector

Kubernetes-commit: 5302055b0780990b878ec24f1907842417336372
2024-09-19 17:19:18 +00:00
Kubernetes Publisher 262825a8a6 Merge pull request #126907 from alegueri/update-example-logs-all-pods
[UPDATE] updating logs examples to contain --all-pods flag

Kubernetes-commit: c53cad79ab4c379908a2e7c9ac8457d4240f0661
2024-09-14 00:13:49 +00:00
Kubernetes Publisher fee9d648a7 Merge pull request #127327 from ryanwinterms/wait_doc
Document the "create" option to the "kubectl wait" command

Kubernetes-commit: 88df7e307b755ea1a0c3223a85d881d9703f2cf7
2024-09-13 16:19:16 +00:00
Ryan Winter 1945b46b05 document the "create" option to the "kubeclt wait" command.
Signed-off-by: Ryan Winter <ryanwinter@outlook.com>

Kubernetes-commit: a3615ce5a38e9ea09339d4b45b843a84e2bf391d
2024-09-12 09:21:37 -07:00
Abhishek Kr Srivastav 36d480f43c Fix Go vet errors for master golang
Co-authored-by: Rajalakshmi-Girish <rajalakshmi.girish1@ibm.com>
Co-authored-by: Abhishek Kr Srivastav <Abhishek.kr.srivastav@ibm.com>

Kubernetes-commit: 95860cff1c418ea6f5494e4a6168e7acd1c390ec
2024-09-12 18:15:22 +05:30
Kubernetes Publisher 3aa701d129 Merge pull request #127271 from liggitt/go1.23
Update go.mod for go 1.23

Kubernetes-commit: c775fb2238e1ed48f62f02898bbb3ecee993e044
2024-09-12 05:56:52 +00:00
Jordan Liggitt 111ebd712e Update k8s.io/gengo/v2
Kubernetes-commit: e7957232cfcfaad1da50252653dea94ac22dc681
2024-09-11 15:38:38 -04:00
Jordan Liggitt 11efae9ae4 Pin godebug default to go1.23
Kubernetes-commit: 102a9dbab1764e8793d0237b25143fa49cd96831
2024-09-10 12:22:40 -04:00
Jordan Liggitt 9ca6564d24 Update go.mod to go 1.23
Kubernetes-commit: 65ef53139012dee36c08f558604dea48af170e11
2024-09-10 12:07:06 -04:00
Kubernetes Publisher e13117fcac Merge pull request #125960 from pohly/dep-logging
dependencies: logr v1.4.2, zap v1.27.0

Kubernetes-commit: a8d4eb60097863210b89063003e537253cf091a8
2024-09-06 20:18:03 +00:00
Kubernetes Publisher 57edd7ccc7 Merge pull request #127011 from jpbetz/format-only-imports
gengo performance: Speed up update-codegen.sh by switching to FormatOnly in gengo

Kubernetes-commit: 95956671d8da7783a726133709b8085f56dda052
2024-09-04 04:24:45 +00:00
Joe Betz 7640fec64e Bump gengo/v2 to pick up FormatOnly setting for imports
Co-authored-by: Tim Hockin <thockin@google.com>

Kubernetes-commit: d5555af62bf25ba9ff0b979fe048b992596cf2cc
2024-09-03 11:32:09 -04:00
Kubernetes Publisher b2a7d2626d Merge pull request #126995 from googs1025/fix/top_cmd
kubectl(top): modify the percentage display of the top command

Kubernetes-commit: e95441591235032994666ff91cfcd77a13d8c7b2
2024-09-02 16:11:16 +00:00
alegueri 9a0e211708 Update logs.go
Kubernetes-commit: ab01874a0658407e1121235591c75f2d6bae0108
2024-08-29 23:52:36 -07:00
googs1025 dca3776905 kubectl(top): modify the percentage display of the top command
Kubernetes-commit: 4209f515eee198dd9192e466cb67a157a2a3d835
2024-08-29 20:44:14 +08:00
Kubernetes Publisher 14f6a11dd8 Merge pull request #126787 from Jefftree/update-kube-openapi
Bump k8s.io/kube-openapi and k8s.io/gengo

Kubernetes-commit: f1a922c8e6f951381450ee3c2922ca018f14a82e
2024-08-28 00:24:41 +00:00
Jefftree b0a9adb1c6 re-vendor k8s.io/kube-openapi
Kubernetes-commit: ea2bdb6334ec1a2821a96163d83480d5fdb1861b
2024-08-27 01:58:39 +00:00
Jefftree 9035822a02 re-vendor k8s.io/gengo/v2
Kubernetes-commit: 6dc87bf173642ff5c8183eb2717377e787e713a9
2024-08-27 01:56:06 +00:00
Kubernetes Publisher c3d194bcd2 Merge pull request #126822 from micahhausler/additional-verbs
Include additional verbs to can-i

Kubernetes-commit: 43968d23073c66c6f82b7aef69dc2d72a2ef7fe2
2024-08-26 18:42:11 +01:00
Alessandra Guerinoni b06b2ef141 [UPDATE] updating logs examples to contain --all-pods flag
Kubernetes-commit: 8bb6e0282ea1ccefe6fd465c7718c560facc888a
2024-08-25 20:10:07 -07:00
Micah Hausler e1b9b58b72 Include additional verbs to can-i
Kubernetes-commit: 08ea67334e1cd664c9f3c34be9a51c0f216183aa
2024-08-20 13:21:55 -05:00
Kubernetes Publisher c4be63c54b Merge pull request #126838 from zou2699/fix-126836
fix: use the getContext() method for evicting pods

Kubernetes-commit: b60e01f881aa8a74b44d0ac1000e4f67f854273b
2024-08-21 20:18:20 +00:00
tux bd15ba4612 fix: use the getContext() method for evicting pods
Kubernetes-commit: cc244e8d1d9d57818816e8e35651b78b0c6f9709
2024-08-21 14:08:57 +08:00
Kubernetes Publisher 4a18df8277 Merge pull request #126652 from ardaguclu/add-timeout-cp-dest-check
Add timeout cancellation to kubectl cp destination path check

Kubernetes-commit: c999f9d828009f0a535237aca74ce2e5f6a8088c
2024-08-16 18:56:52 +00:00
Arda Güçlü 2c705c6f91 Increate timeout to 10sec and shortcut when ctx deadline is exceeded
Kubernetes-commit: ca2c9c64b489d14352e9b6f4c827506a5653a569
2024-08-16 16:13:01 +03:00
Kubernetes Publisher 823a551020 Merge pull request #126715 from tklauser/use-go-stdlib-slices
Use Go standard library slices package instead of k8s.io/utils/strings/slices

Kubernetes-commit: 1dd3c64502dfd07137f311fed63408af9c0c2513
2024-08-16 02:54:15 +00:00
Tobias Klauser d80cbcdb4d Use Go standard library slices package instead of k8s.io/utils/strings/slices
The package was introduced in Go 1.21 and is already in use in the k8s
code base.

Kubernetes-commit: 23dcd2604883c7ba91d72f5a9d84706650260c55
2024-08-15 14:43:53 +02:00
Kubernetes Publisher cf5c214b25 Merge pull request #126706 from carlory/kubectl-describe-image-volume
show image volume when kubectl describe a pod with image volume

Kubernetes-commit: ab26ad095029eb46ca2e938ac3a16cb6f164e657
2024-08-15 15:26:13 +00:00
carlory c63fb82d09 Fix print volume when kubelet describe a pod with image volume
Kubernetes-commit: bd32f542e9bba4a1eca31818cbd79db9801ab2e5
2024-08-15 18:00:13 +08:00
Benjamin Elder ee337ad2d6 kuebctl cp: discard output from test command
we only care about the exit code

see https://github.com/kubernetes/kubernetes/issues/126669

Kubernetes-commit: 78ae67a90042aa6ed5e91fc5730c10f26ba8d7f6
2024-08-14 16:58:02 -07:00
Kubernetes Publisher 03a826a301 Merge pull request #126545 from yangjunmyfm192085/updatepersistentVolumeClaimRetentionPolicy
Update incorrect description of persistentVolumeClaimRetentionPolicy

Kubernetes-commit: 6a478b4306ea9ae3b8f86bd1ef71072d9a03be22
2024-08-14 07:03:07 +00:00
Arda Güçlü 4fe61440d3 Add timeout cancellation to kubectl cp destination path check
Kubernetes-commit: d981b19ad30c3396e8a4d197bedc346e68e0270b
2024-08-13 11:02:04 +03:00
Kubernetes Publisher 3f1b31120b Merge pull request #126638 from soltysh/fix_wait
wait: don't lowercase condition in --for argument

Kubernetes-commit: 099a88370d017dacf16e67306ebcdec8394fae83
2024-08-12 17:23:00 +00:00
Maciej Szulik 8f2f49349b wait: don't lowercase condition in --for argument
Kubernetes-commit: fad6c424ac9b69229e02f9d9058c8131005f86e2
2024-08-12 16:30:20 +02:00
Jingyuan Liang 619e8f9f0d kubectl/describe: use function calls to build field selector
Instead of using string concatenation.

Signed-off-by: Jingyuan Liang <jingyuanliang@google.com>

Kubernetes-commit: a2dc34cb17c2eb9981b80cd9a550559f3a74ce23
2024-08-08 00:53:04 +00:00
杨军10092085 acdf12bd01 Updated incorrect description of persistentVolumeClaimRetentionPolicy
Kubernetes-commit: 56bbae4807989cd43eff17cf9fa93f7b54c087bd
2024-08-05 21:30:25 +08:00
Kubernetes Publisher 2e31adb070 Merge pull request #126145 from carlory/kep-3751-api
[KEP-3751] Promote VolumeAttributesClass to beta

Kubernetes-commit: c2fdeca4ab81336daf20c91b810c9685918c3d58
2024-07-24 01:56:00 +00:00
carlory 05a8bf872e Promote VolumeAttributesClass to beta
Kubernetes-commit: 0260c7d023551f85621049ca604a4fd5110ba0a9
2024-07-17 15:55:06 +08:00
Kubernetes Publisher b315eb8455 Merge pull request #126231 from seans3/websocket-https-proxy-fix
Falls back to SPDY for gorilla/websocket https proxy error

Kubernetes-commit: 90a84704d6e103c0a7b5cdaa8f6626a134079147
2024-07-20 23:27:39 +00:00
Sean Sullivan 2c588bc5ed Falls back to SPDY for gorilla/websocket https proxy error
Kubernetes-commit: 9d560540c5268e0e2aebf5306907494cf522c260
2024-07-19 12:04:41 -07:00
Kubernetes Publisher b4d17b87f5 Merge pull request #126173 from bergerhoffer/cli-help
A few minor help text tweaks

Kubernetes-commit: 45cb3a1bd063b412d2b43b01d7a94ec2fca1ac4f
2024-07-18 03:25:24 +00:00
Andrea Hoffer 60dccb9d13 A few minor help text tweaks
Kubernetes-commit: 5252f79f9bd1142bf838aeaf8168ca7fe7616445
2024-07-17 13:30:34 -04:00
Kubernetes Publisher 072e9981f1 Merge pull request #126018 from aroradaman/bump-k8s-utils
bump k8s.io/utils

Kubernetes-commit: 46aa8959a0659e22c924bb52b38385d441715b2b
2024-07-13 19:27:15 +00:00
Daman Arora d0ed078ea5 bump k8s.io/utils
Signed-off-by: Daman Arora <aroradaman@gmail.com>

Kubernetes-commit: c6a129b715646163ef83f94245c3756cbc191c42
2024-07-12 14:40:22 +05:30
Kubernetes Publisher 58672617cf Merge pull request #125802 from mmorel-35/testifylint/len+empty
fix: enable empty and len rules from testifylint on pkg and staging package

Kubernetes-commit: 2d4514e1690dc5babb144542da799f6b331afd1b
2024-07-12 07:25:34 +00:00
Kubernetes Publisher 15aefcb085 Merge pull request #125868 from soltysh/wait_for
Add --for=create option to kubectl wait

Kubernetes-commit: 37f733a657ef71d66177d00f9b7d47ec507dedd3
2024-07-11 17:09:58 +00:00
Kubernetes Publisher eaa3175fb1 Merge pull request #125333 from ardaguclu/kep-4292-beta
KEP-4292: Preparations to promote custom profiling in kubectl debug

Kubernetes-commit: c20aa764d787d5710935b573571c0574b2e13e47
2024-07-11 17:09:56 +00:00
Patrick Ohly 78100b683e dependencies: logr v1.4.2, zap v1.27.0
No particular reason for updating besides staying up-to-date.

Kubernetes-commit: 861ed2d2feeca187a32dcf793c9e3d5ab21bfdfc
2024-07-08 17:51:59 +02:00
Maciej Szulik df17d35554 Add --for=create option to kubectl wait
Kubernetes-commit: aaf1fb50f32466aa5e845ff423fc4acc8f04c402
2024-07-08 13:32:31 +02:00
Kubernetes Publisher a6de79e3d4 Merge pull request #124994 from TessaIO/fix-autocompletion-for-set-context-namespace
fix: add namespace autocompletion for kubectl config set-context command

Kubernetes-commit: 7ec344dcef9a04920578aabe4e122bc0b3404afe
2024-07-08 07:19:59 +00:00
Kubernetes Publisher a421f02b7c Merge pull request #125922 from dims/update_otel_27
Update opentelemetry dependencies to the latest release (Take 2)

Kubernetes-commit: 07cc20a7509e7322e6ebb04e60d8274f27d6fdd7
2024-07-07 03:29:03 +00:00
Davanum Srinivas 07726d29e8 update OpenTelemetry dependencies and grpc
This update dropped the otelgrpc → cloud.google.com/go/compute dependency,
among others. This dropped out because genproto cleaned up it's dependencies
on google cloud libraries, and otel updated - details in #113366.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
Co-Authored-By: David Ashpole <dashpole@google.com>

Kubernetes-commit: ff7942be83ed0c0aaa8c258e8e2b9965d383935c
2024-07-05 12:10:07 -04:00
Kubernetes Publisher 68dbd0767a Merge pull request #125842 from soltysh/remove_deprecated_flags
Remove deprecated kubectl run and drain flags

Kubernetes-commit: 8ebfb8c2c2dcc5089390eeb383520e8310bf7423
2024-07-04 06:46:32 -07:00
Maciej Szulik 1c0cdd03d9 kubectl wait: split condition functions into separate files
Kubernetes-commit: 6eec9d6b21316833bc66b1586207d5b2326b35fe
2024-07-03 11:27:08 +02:00
Maciej Szulik 5eeba3a134 Remove deprecated kubectl drain flag
delete-local-data was deprecated back in v1.20 with this commit:
625e47aaa2

It's about time we entirely drop the support for this flag. Users should
be already using delete-emptydir-data instead.

Kubernetes-commit: 4b5cf0a2766c02ba88b5d104a79c16b1f1f367b6
2024-07-02 15:48:40 +02:00
Matthieu MOREL 1a58d7f437 fix: enable empty and len rules from testifylint on pkg package
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>

Co-authored-by: Patrick Ohly <patrick.ohly@intel.com>

Kubernetes-commit: f014b754fb5925dfbca6e27a44d0c3968b157e14
2024-06-28 21:20:13 +02:00
Maciej Szulik b3015b8e3e Remove deprecated kubectl run flags
This commits removes the following flags from kubectl run:
- filename
- force
- grace-period
- kustomize
- recursive
- timeout
- wait

Those flags are deprecated since v1.26, see this commit
09804a198c.

Kubernetes-commit: f1917f18eb715353610b6dfa0744698fa3fa7654
2024-06-26 17:42:13 +02:00
Kubernetes Publisher b2d7179a03 Merge pull request #125021 from aojea/servicecidrbeta
KEP-1880 Multiple Service CIDRs: Graduate to Beta (2/2)

Kubernetes-commit: 93d56511e684369479f23aae15617e483cda5719
2024-06-30 19:13:32 +00:00
Antonio Ojea 69ef2e6a97 use networking v1beta1 for kubectl describe
Kubernetes-commit: c1d06c0ae421f180d0179e89daa1409e6d14bd7c
2024-06-29 10:04:47 +00:00
Kubernetes Publisher 172bb858a6 Merge pull request #125759 from dims/bump-prometheus/common-v0.55.0
Bump `prometheus/common` to v0.55.0

Kubernetes-commit: 4c44efe81c9a26d66cdf88e917aeee75dad12299
2024-06-28 07:18:24 +00:00
Kubernetes Publisher 2f6a8aff11 Merge pull request #125766 from dims/update-moby/spdystream-to-v0.4.0
Update moby/spdystream to v0.4.0

Kubernetes-commit: 742b2f70b9e5c1ec03682ad25dc76fdcc7109310
2024-06-27 23:18:04 +00:00
Kubernetes Publisher 980dabe2f2 Merge pull request #125646 from HirazawaUi/apply-null
Prune explicit nulls from client-side apply create

Kubernetes-commit: 991e7a8c15cbf959cd67bf92fd5e8adfd6875406
2024-06-27 19:16:08 +00:00
Davanum Srinivas 3b755991af Update moby/spdystream to v0.4.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 377a3f7ec4dc2b5e09e0aadb651999d400c31538
2024-06-27 13:07:47 -04:00
Davanum Srinivas 582c9dabb0 Bump `prometheus/common to` v0.55.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 35ccdc8b35f1c4346071d4ff0efecdd7a6bcdecc
2024-06-27 07:58:24 -04:00
Kubernetes Publisher e91710120d Merge pull request #125745 from BenTheElder/ping-ping
bump  github.com/moby/spdystream to v0.3.0

Kubernetes-commit: 11446a394fb851d3496d31d96a67f8fcba6348e3
2024-06-26 23:20:35 +00:00
Quan Tian 770b201e9c Make the output of `kubectl describe service` more informative (#125117)
* kubectl: add internalTrafficPolicy to Service describer

* kubectl: add loadBalancer ipMode to Service describer

* kubectl: fix duplicate IP fields in Service describer

For a LoadBalancer Service, there were two "IP" fields in the output of
`kubectl describe service` if its loadBalancerIP is not empty, which
looks ambiguous.

Kubernetes-commit: 59d90eb17e41f855e65f6ca4ac3d93d3709a3067
2024-06-26 23:20:34 +00:00
Benjamin Elder dcb1192020 bump github.com/moby/spdystream to v0.3.0
picks up fix for data-race in Ping

Kubernetes-commit: c5aa8fdc711982dd589a9ac940b05297cc46b4a5
2024-06-26 12:27:14 -07:00
Kubernetes Publisher 42f728c3d6 Merge pull request #125731 from dashpole/revert_otel
Revert "Update opentelemetry dependencies to the latest release."

Kubernetes-commit: a4b8d0faa8e7d3227cbdda39241998d38f1c294e
2024-06-26 19:19:51 +00:00
David Ashpole 872eb0883e Revert "update OpenTelemetry dependencies"
This reverts commit 82e9ce79c763f1028f542b1246114082430e6b20.

Kubernetes-commit: e94047c9002c17a3b76513c3cde2d53aed39b7fb
2024-06-26 14:13:33 +00:00
Kubernetes Publisher c5396bb9d0 Merge pull request #125669 from benluddy/cbor-bump-v2.7.0
KEP-4222: Bump github.com/fxamacker/cbor/v2 to v2.7.0.

Kubernetes-commit: beb48b7f5df83cd56275f471e52ef588ba845093
2024-06-26 08:23:26 +00:00
Ben Luddy a9fe9eb5f7 Bump github.com/fxamacker/cbor/v2 to v2.7.0.
Kubernetes-commit: dbe4c093d9f5b85fa509042556edf61fb6503b22
2024-06-24 09:49:40 -04:00
Kubernetes Publisher 269ced5ce8 Merge pull request #125575 from dashpole/update_otel_27
Update opentelemetry dependencies to the latest release.

Kubernetes-commit: 535e833aef9718d1a19a8f71b3a4639fc92aa855
2024-06-26 08:23:25 +00:00
David Ashpole 6c46eadd33 update OpenTelemetry dependencies
Kubernetes-commit: 82e9ce79c763f1028f542b1246114082430e6b20
2024-06-19 00:43:16 +00:00
Kubernetes Publisher 7e6366765e Merge pull request #125630 from liggitt/rollback-wait
Revert kubectl wait regression

Kubernetes-commit: da479a82ebb6d4117b69f2c78364c81a513ad511
2024-06-21 22:51:46 +00:00
Arda Güçlü d5a8f05803 Remove deprecated kubectl exec command execution without dash (#125437)
* Remove deprecated kubectl exec command execution without dash

* Use command execution with dash in kubectl exec

* Modify unit tests to only use command after dash

Kubernetes-commit: 6f4e97e905e5553e75a5a8c042c9f5a29bd1b78d
2024-06-21 19:22:55 +03:00
Jordan Liggitt 3f7d004bdf Revert "Add new --wait-for-creation flag in kubectl wait command"
This reverts commit e24b9a022f3b1e97ea538c9754d4d38f119f275e.

Kubernetes-commit: 8d67437865a8e1abaed0b813d6913b412f7ed2b4
2024-06-21 12:13:08 -04:00
Kubernetes Publisher f508e12184 Merge pull request #122994 from ardaguclu/wait-non-existed-resources
kubectl wait: Introduce --wait-for-creation flag

Kubernetes-commit: b95fce1732016c06501ca5a1aa5452b55149a2d5
2024-06-20 22:55:06 +00:00
Kubernetes Publisher 6921b6008e Merge pull request #125531 from pohly/klog-update
dependencies: klog v2.130.1

Kubernetes-commit: 44446e1c9c2e7f50061f2a998c76f6f55f3ca737
2024-06-20 19:01:09 +00:00
Patrick Ohly 030f865b1b dependencies: klog v2.130.1
Kubernetes-commit: f98e5d1dfcaa37fee2c394436583038cf3ff1e72
2024-06-16 14:04:43 +02:00
Kubernetes Publisher d187b13731 Merge pull request #125574 from jpmcb/cobra-1.8.1
Upgrade spf13/cobra v1.8.1

Kubernetes-commit: 52e4fbdd85bae16891c05235c22ad01f52f82bd4
2024-06-20 02:53:42 +00:00
John McBride 8a8cd02be0 feat: Upgrade to cobra v1.8.1
Signed-off-by: John McBride <jpmmcbride@gmail.com>

Kubernetes-commit: 5aaff7d060b8de6b5aea53ef64e0ef7a8be74abd
2024-06-18 18:11:39 -06:00
Kubernetes Publisher 97bc4a2eb7 Merge pull request #125573 from dims/update-moby/term-to-a-released-tag-v0.5.0
Update moby/term to a released tag - v0.5.0

Kubernetes-commit: 1e66d66d7c79dec3a199254268d0754ad66ae7d4
2024-06-19 18:54:05 +00:00
Davanum Srinivas d087fa13f4 Update moby/term to a released tag - v0.5.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: e457f5687ac58e60652b7c2d678d0aefc9bb83d4
2024-06-18 19:58:55 -04:00
Kubernetes Publisher e799af9379 Merge pull request #125528 from seans3/port-forward-beta
PortForward over Websockets Graduates to Beta

Kubernetes-commit: ef9965ebc66dafda37800bb04f5e284535bbba10
2024-06-16 22:55:44 +00:00
Sean Sullivan 13611d4701 Graduate PortForwardWebsockets to Beta
Kubernetes-commit: 3ae3b4ea551443d8ef695d31bf0c51963fe35ac3
2024-06-15 16:09:23 -07:00
Kubernetes Publisher 3802ec81a2 Merge pull request #125444 from babugeet/babugeet-patch-1
Added logic to check portnumber by name in sidecar container (init)

Kubernetes-commit: cf0b4576905538ac1a74547f2b8567842b5492c7
2024-06-12 19:00:55 +00:00
Kubernetes Publisher ce7ca659e3 Merge pull request #122038 from lowang-bh/fixPodshow
show pod Status as phase Failed or Succeeded if it has deletionTimestamp

Kubernetes-commit: b669abc18163a703d1db5ae3c32fd2faff1694b3
2024-06-12 16:51:19 +00:00
babugeet 0b359223b4 Added logic to check portname in sidecar container (init)
Signed-off-by: "babugeet <abhinandhbg@gmail.com>"

Kubernetes-commit: 7a810c6bb6591c4d617b585144d8f54ebaaed334
2024-06-11 20:05:39 +05:30
Kubernetes Publisher 041879def4 Merge pull request #125408 from benluddy/bump-cbor-v2.7.0
KEP-4222: Bump github.com/fxamacker/cbor/v2.

Kubernetes-commit: 6346b9d1327c4b8be2398d9715bdae5475e27569
2024-06-11 01:43:38 +00:00
Arda Güçlü cefe6cb0a0 Add yaml format custom profiling support
Kubernetes-commit: e8f473036197b14d33df10b76de8a1c8b12f79ce
2024-06-04 15:06:45 +03:00
Arda Güçlü 157dc2e404 Enable custom profiling in kubectl debug as default
Kubernetes-commit: 4e650a995412d60ace07ab67b556137b0bcba1be
2024-06-04 14:59:17 +03:00
Jordan Liggitt 81ad0ffc39 Prune explicit nulls from client-side apply create
Kubernetes-commit: 8483b9c08763c8f615216e95efdde46d5c7f6ef7
2024-05-29 01:14:18 -04:00
Josh Soref 209732ca71 chore: Order ScalingReplicaSet message from->to
* change format of event
* include `from 0` for new replicas
* update describe tests to reflect current output

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

Kubernetes-commit: 502c05ed019573e8ed43c412f739882eec0f5f7c
2024-05-24 12:18:06 -04:00
TessaIO 25c985cf66 fix: add namespace autocompletion for kubectl config set-context command
Signed-off-by: TessaIO <ahmedgrati1999@gmail.com>

Kubernetes-commit: 62be85249e27e58a92ab3a1caf672159dc3cfd7f
2024-05-20 14:44:54 +02:00
AxeZhan 4657409ea3 consider sidecar containers in maxContainerRestarts
Kubernetes-commit: 7533123eb5e7c6ecd59d00d236235581f7f1157b
2024-05-19 23:50:25 +08:00
Ben Luddy 290ff2d971 Bump fxamacker/cbor/v2 to v2.7.0-beta.
This library release makes a number of behaviors configurable in ways that are required for CBOR
support in Kubernetes.

Kubernetes-commit: c4279660cad039bc15495311cf7863640b6308f9
2024-05-09 14:30:58 -04:00
Kubernetes Publisher f74c97d4ab Merge pull request #125238 from munnerz/kep-4193-nodebinding-beta
KEP-4193: promote ServiceAccountTokenNodeBinding feature to beta

Kubernetes-commit: 790dfdbe386e4a115f41d38058c127d2dd0e6f44
2024-05-31 21:26:03 +00:00
Kubernetes Publisher 21275cf4d0 Merge pull request #124916 from TessaIO/test-improve-unit-tests-for-container-name-autocompletion
test: improve unit tests for container name autocompletion

Kubernetes-commit: 723c2696411a282f5d4441b6bf61cc5173cd0e45
2024-05-31 21:26:02 +00:00
James Munnelly b57bb4f06e KEP-4193: promote ServiceAccountTokenNodeBinding feature to beta
Kubernetes-commit: 5481e630dea4c57c31b65a4fadf1bbeca77c2c57
2024-05-31 12:16:03 +01:00
Kubernetes Publisher f183fdb3b3 Merge pull request #122832 from benluddy/cbor-fuzz-native-to-unstructured-via
KEP-4222: Add roundtrip tests to Unstructured via CBOR and JSON.

Kubernetes-commit: f30a87d517c538f22e1d84b4d7c497f57f7b760a
2024-05-31 01:34:23 +00:00
Kubernetes Publisher 6b4730ae70 Merge pull request #112104 from oldium/fix-windows-editor-launch
Fix editor launch with Windows cmd.exe when KUBE_EDITOR has spaces in path

Kubernetes-commit: c811521331ee09d9fce7b866d5c8c79f45ba4125
2024-05-30 17:26:57 +00:00
Kubernetes Publisher 79f145bee1 Merge pull request #123440 from Ritikaa96/kubectl-improve-get
Improving kubectl get output

Kubernetes-commit: 36f1d73c1f14f1639ea37552fae78ba89c6638e8
2024-05-30 17:26:55 +00:00
Ritikaa96 24a31a929b correcting description as per review
Signed-off-by: Ritikaa96 <ritika@india.nec.com>

Kubernetes-commit: b9ec8b3c4643c36491ba94e48e6b957828c850cb
2024-05-30 11:53:02 +05:30
Kubernetes Publisher d3ad753245 Merge pull request #123339 from skitt/canonical-json-patch
Update kustomize, use canonical json-patch v4 import

Kubernetes-commit: da02fdb2aef1b7102526963c91df4992ee5b6a05
2024-05-29 21:35:21 +00:00
Kubernetes Publisher 627b5dabb0 Merge pull request #125131 from ah8ad3/auth-cani-approve
Add approve as a valid verb in can-i

Kubernetes-commit: 7ba244f50e57257e9d435b42f3b0f17a92a0611a
2024-05-29 09:25:26 +00:00
Kubernetes Publisher 382ad8ff11 Merge pull request #125045 from pohly/ginkgo-gomega-update
dependencies: ginkgo v2.19.0, gomega v1.33.1

Kubernetes-commit: 1c84623028b496e22d8401100ef6f59325e092e0
2024-05-28 09:35:13 +00:00
Kubernetes Publisher e06e0c6134 Merge pull request #124232 from Ritikaa96/kubectl-plugin
Added name-only and examples in the kubectl plugin help

Kubernetes-commit: d45a1a493bcb1f8a18ece00c1f9e0425d3e7272d
2024-05-27 17:29:31 +00:00
Ritikaa96 ff551a76e3 correcting link to krew install
Signed-off-by: Ritikaa96 <ritika@india.nec.com>

Kubernetes-commit: 23ac0be7adf9212bec4771a351417a1142520485
2024-05-27 16:52:19 +05:30
ah8ad3 e5da5e005a add approve as a valid verb in can-i
Kubernetes-commit: 12684aacefd3d4a2ba4eecded14086a0b626431b
2024-05-26 15:02:09 +03:30
Patrick Ohly 5b2540dc63 dependencies: ginkgo v2.19.0, gomega v1.33.1
Ginkgo v2.18.0 allows tweaking the output so that
it's easier to follow while a job runs in
Prow (https://github.com/onsi/ginkgo/issues/1347). Using this in
hack/ginkgo-e2e.sh will follow in a separate commit.

Gomega gets bumped to the latest release to keep it up-to-date.

Ginkgo v1.19.0 adds support for --label-filter with labels that represent
sets (like our Feature:<Foo>).

Kubernetes-commit: 37e2dd6857084a172ef5210caee1fefa8dd8159a
2024-05-22 10:22:09 +02:00
Ben Luddy dec98f7709 Update indirect dependencies with ./hack/update-vendor.sh.
Implementing custom marshaling on several API types for CBOR makes the upstream CBOR library an
indirect dependency of several staging modules.

Kubernetes-commit: d7cccf3e792ad08d9ab2e7aac394f8e6ddcf3466
2024-05-17 13:02:26 -04:00
TessaIO b56ea4761e test: improve unit tests for container name autocompletion
Signed-off-by: TessaIO <ahmedgrati1999@gmail.com>

Kubernetes-commit: fe81d0d5ac32c59bce138291cfcdaf5422617b06
2024-05-16 21:40:50 +02:00
Ritikaa96 8941dd6b94 added name-only and examples in the kubectl plugin help
Signed-off-by: Ritikaa96 <ritika@india.nec.com>

Kubernetes-commit: 3848c8b07a4b09d6fe9c8ea88b4229c6f637baf4
2024-04-08 15:02:36 +05:30
Kubernetes Publisher 85119a1e56 Merge pull request #125112 from neolit123/1.31-add-v-to-windows-pause-after-promo
dependencies: start using registry.k8s.io/pause:3.10

Kubernetes-commit: e0e6c9633d5f9a388cbf9c7757c789afaec11c34
2024-05-24 03:55:56 -07:00
Lubomir I. Ivanov fe3be32c18 switch k/k to pause version 3.10
Kubernetes-commit: 5e290ebc906fd16d956b09f4834393716dd90f94
2024-05-23 14:01:39 +03:00
Kubernetes Publisher 0bd9881b18 Merge pull request #125072 from brianpursley/create-fix-validation
Fix validation of -f or -k flag in kubectl create command to be consistent with other commands

Kubernetes-commit: c9a1a0a3b8acb70cba30d6f4ea59505b4564b4d9
2024-05-23 09:26:31 +00:00
Brian Pursley df7520c1f3 Fix inconsistent validation of -f or -k flag in kubectl create command
Kubernetes-commit: 4fddd6a3cda9c95c8ae5b4a36d3c3fb06aa1dce1
2024-05-22 15:36:28 -04:00
Kubernetes Publisher 7d69e0104e Merge pull request #125049 from srivastav-abhishek/flake-fix-logs-test
fixed flaky test TestLog/stateful_set_logs_with_all_pods by splitting expected output string

Kubernetes-commit: 84a7f1ea15e4fcabe88e06ca27de611fa3b74437
2024-05-22 09:11:30 -07:00
Abhishek Kr Srivastav a4551ef19a fixed flaky test by splitting expected output string
addressed review comments

Kubernetes-commit: 5de6f7cf6167b04892750423228ccd61ac09ddd4
2024-05-22 14:52:52 +05:30
Ahmad Zolfaghari 55821cad07 Fix kubectl explain bug when additionalProperties in schema defines as boolean. (#124506)
* Fix kubectl explain bug when additionalProperties in schema defines as:
`additionalProperties: true` to ignore iterating.

* trigger error on kubectl explain with integration test on crd with non bool additionalfields

* add changes to fix the problem

* replace sleep with loop and retry for kubectl explain integration test

* replaced testdata file with inline create

Kubernetes-commit: 834658cb26c1cfbb2b41ac2f04711563ee534682
2024-05-21 13:29:06 +00:00
Kubernetes Publisher b31dce3246 Merge pull request #125005 from brianpursley/fix-deprecated-ptr
Use ptr.To instead of deprecated pointer functions

Kubernetes-commit: 62aae86899a7b780eb1e8805fbcaf0fb6a5baa14
2024-05-21 05:24:31 +00:00
Brian Pursley 8d8b5a6120 Use ptr.To instead of deprecated pointer functions
Kubernetes-commit: 288d132cf62efe029b6359c600565f8c7b12647d
2024-05-20 16:14:54 -04:00
Kubernetes Publisher 5b7c8b24b4 Merge pull request #123149 from mochizuki875/remove_probe_from_copy_pod
kubectl debug: Add --keep-* flag to control the removal of probes, labels, annotations, and initContainers from copy pod

Kubernetes-commit: 6d4250ed413223c2f0a1ab8c253780bf43747bb6
2024-05-17 05:24:06 +00:00
Kubernetes Publisher bfb7f4aa02 Merge pull request #124883 from ardaguclu/create-cronjobs-role-fix
kubectl create cronjobs: Manually set OwnerReferences

Kubernetes-commit: 466b10fcabd92cf1c1f250522c6e2c5d1045747c
2024-05-15 04:39:11 -07:00
Arda Güçlü 2e9d71e05d kubectl create cronjobs: Manually set OwnerReferences
Kubernetes-commit: 11c0c8bb705f3c4f5dac00f8b0ddbec6a95cd7aa
2024-05-15 13:31:31 +03:00
Kubernetes Publisher b9d568d7e4 Merge pull request #124732 from cmwylie19/1520
feat: add all-pods log flag to kubectl

Kubernetes-commit: 9f39314eb9b1f0127500cf7f0983fb00f90d49d1
2024-05-14 17:20:53 +00:00
Kubernetes Publisher 5450795bac Merge pull request #124683 from TessaIO/feat-add-portforward-autocompletion
feat: add ports autocompletion for kubectl port-forward command

Kubernetes-commit: 5e1a1db960660194a00f4ae7d6c9195b3c1715a6
2024-05-13 17:19:50 +00:00
Kubernetes Publisher 514f46729f Merge pull request #124757 from dims/update-to-latest-golang.org/x/oauth2-v0.20.0
Update to latest golang.org/x/oauth2 v0.20.0

Kubernetes-commit: 22578c545ffc04a505a7a64c9b8f6c78fefa07ef
2024-05-09 01:32:39 +00:00
Davanum Srinivas 8288417631 Update to latest golang.org/x/oauth2 v0.20.0
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 04c40ac96134d7f7bf697d0a58caf0f8b0380075
2024-05-08 11:04:34 -04:00
Kubernetes Publisher 57112bd241 Merge pull request #123619 from Eduard-Voiculescu/warning-watch-only-msg
show warning message only when running `kubectl get --watch-only`

Kubernetes-commit: f1385904eac7ca234f33e2b45d752c2013bfde4a
2024-05-08 05:22:21 +00:00
Case Wylie b1dfef4f42 feat: add all-pods log flag to kubectl
Signed-off-by: Case Wylie <cmwylie19@defenseunicorns.com>

Kubernetes-commit: 6db859eb5de14d748ace74974951697477848ee9
2024-05-07 19:43:46 -04:00
Kubernetes Publisher 0f357874d3 Merge pull request #124514 from brianpursley/fix-sort
Change non-quantity strings to sort alphanumerically, instead of using "Natural Sort"

Kubernetes-commit: f281a02d236d1112009c54062b99972ea6e4e731
2024-05-07 21:23:01 +00:00
Kubernetes Publisher f825bd0b72 Merge pull request #124592 from ah8ad3/add-kubectl-set-completion
Add completion for kubectl set image

Kubernetes-commit: 0590bb1ac495ae8af2a573f879408e48800da2c5
2024-05-07 09:18:54 +00:00
Kubernetes Publisher 6985b81ab4 Merge pull request #124598 from aroradaman/kubectl-describe-svc
Use endpointSlices for describing service endpoints

Kubernetes-commit: 44bd04c0cbddde69aaeb7a90d3bd3de4e417f27f
2024-05-06 17:26:21 +00:00
TessaIO 5f33246cf8 feat: add ports autocompletion for kubectl port-forward command
Signed-off-by: TessaIO <ahmedgrati1999@gmail.com>

Kubernetes-commit: a84e893afa2d4fdd1e42ee6047812ff46daa9296
2024-05-01 23:33:39 +02:00
Daman Arora 649e09882b kubectl/describe: use endpointslices for describing endpoints
Signed-off-by: Daman Arora <aroradaman@gmail.com>

Kubernetes-commit: 3236891023c991f1b66a49b8c9f6331ed6b4a690
2024-05-01 15:09:02 +05:30
Daman Arora 5aca4630e4 kubectl/describe/svc: refactor TestDescribeService
Signed-off-by: Daman Arora <aroradaman@gmail.com>

Kubernetes-commit: df417aa9b8813d0e5e1208e9039f140edeff39db
2024-05-01 14:45:45 +05:30
Kubernetes Publisher 771a13a844 Merge pull request #124597 from TessaIO/fix-drain-error-message
fix: add whitespace to drain error message

Kubernetes-commit: dd68c5f2409fec7176e6172d6f9d97bd6447c4da
2024-04-30 22:07:49 +00:00
Kubernetes Publisher 5ff591adc6 Merge pull request #124562 from sbueringer/pr-bump-sigs-yaml
Bump sigs.k8s.io/yaml to v1.4.0

Kubernetes-commit: c1ef6c44f5d7b582bf19669c6dbf2ff9552b9d6c
2024-04-29 22:15:06 +00:00
TessaIO 3d99e3ab7e fix: add whitespace for drain error message
Signed-off-by: ahmed.g <ahmed.g@adjoe.io>

Kubernetes-commit: 487f83500faadc8ec972aa164b07940476288e2f
2024-04-28 17:51:06 +02:00
ah8ad3 c572c1d825 Add completion for kubectl set image
Kubernetes-commit: ee58214bfb909c27222b635c55e2043c776cf211
2024-04-28 14:04:48 +03:30
Kubernetes Publisher 4f380d07c5 Merge pull request #124494 from brianpursley/FixSlowUnitTest-TestForceApply
Improve performance of TestForceApply unit test (k8s.io/kubectl/pkg/cmd/apply)

Kubernetes-commit: 8718b3336609b8962a7dac464d8a39a0c2ddb65c
2024-04-26 22:07:57 +00:00
Stefan Bueringer 801b2f2907 Bump sigs.k8s.io/yaml to v1.4.0
Kubernetes-commit: 04cc45b4adda1b19d5067d45ed246c0f84fed966
2024-04-26 15:28:17 +02:00
Brian Pursley 150571ea52 Change non-quantity strings to sort alphanumerically, instead of using "Natural Sort", which is confusing for users.
Kubernetes-commit: 322aa9a649de1db9f9a18889a3c249ec841d2127
2024-04-24 14:59:37 -04:00
Kubernetes Publisher 4196229029 Merge pull request #124469 from serathius/etcd-3.5.13
Upgrade etcd libraries to v3.5.13

Kubernetes-commit: 0f063280964b09e0e21c8cc457a181c20c68da61
2024-04-24 18:13:26 +00:00
Brian Pursley 852454f7f7 Improve performance of TestForceApply unit test.
Change backOffPeriod from const to var, so that it can be set lower during unit test.

Kubernetes-commit: f011ed5ca5b23971f2dc620971b3b5bebb346b84
2024-04-23 22:04:38 -04:00
Marek Siarkowicz 1cb4e5b9e2 Upgrade etcd libraries to v3.5.13
Add otelgrpc.WithMessageEvents(otelgrpc.ReceivedEvents, otelgrpc.SentEvents) to tracing options due to https://github.com/open-telemetry/opentelemetry-go-contrib/pull/3964

Kubernetes-commit: 3e5b03eb433ee359782f5aa6e9368ab2a0d0370c
2024-04-23 11:10:37 +02:00
Kubernetes Publisher d0e936c703 Merge pull request #124328 from jiahuif-forks/deps/cel-go
bump cel-go to v0.20.1 and refit CEL libraries

Kubernetes-commit: 16a594f907d0d4a6224dab2d0704793d5e7898f6
2024-04-23 02:14:49 +00:00
Jiahui Feng 94aa535f7b generated: ./hack/update-vendor.sh
Kubernetes-commit: 350fcf957e90501f0b224b7ccf771b29d4d5c6b6
2024-04-22 10:54:32 -07:00
Jiahui Feng 41b0711fd3 generated: ./hack/pin-dependency.sh github.com/google/cel-go v0.20.1
Kubernetes-commit: 94997c6fefa2791192d0a7ab68b02bf5d8b6c2c5
2024-04-15 13:33:10 -07:00
Kubernetes Publisher 32e71fd995 Merge pull request #124346 from jwcesign/master
upgrade: upgrade dependencies github.com/prometheus/common to the newest version

Kubernetes-commit: 76de052680da0b7a59b35fb79db7ab322faf2854
2024-04-22 18:14:43 +00:00
Kubernetes Publisher f0276dce1a Merge pull request #123900 from rmiki/task/123899
[ja]fix typo in "kubectl config delete-context -h"

Kubernetes-commit: 89463486362f747ee132da55d44ac9c9b40b03ed
2024-04-22 14:07:56 +00:00
Kubernetes Publisher 04bb64c802 Merge pull request #119589 from carlory/fix-kubectl-1439
fix unusable secret manifest for type docker-registry

Kubernetes-commit: d1b2490c80fd5c3e0d90598477f62a70d8099bb2
2024-04-19 22:08:19 +00:00
Kubernetes Publisher 389b2eeaf6 Merge pull request #113257 from claudiubelu/path-filepath-update-staging
Replaces path.Operation with filepath.Operation (staging)

Kubernetes-commit: 80542ca2e318f6f82429822b267497570b7ecca5
2024-04-18 18:14:03 +00:00
Kubernetes Publisher 54dfe4c559 Merge pull request #124123 from sttts/sttts-kubectl-plugin-positional
kubectl: fix plugin lookup with positional arguments

Kubernetes-commit: ca4a864336bdb1d61bc19e90a9c81ac6c661e6d7
2024-04-18 14:12:09 +00:00
Kubernetes Publisher b465426392 Merge pull request #124045 from amirsadraabdollahi/fix/kubectl/expose
Fix: correct dryRunStratergy typo in kubectl expose cmd

Kubernetes-commit: 16c0213b11af8f4643d0d478782f56949642ded3
2024-04-18 10:13:56 +00:00
Kubernetes Publisher adfcfcf7c1 Merge pull request #123597 from siddhantvirus/master
Improving legibility of kubectl describe configmap output

Kubernetes-commit: 9d945ba5a520438ac8cf7a77200ae6a8d2d8bd4b
2024-04-18 10:13:55 +00:00
Kubernetes Publisher 25dbaefaa9 Merge pull request #123316 from jcaamano/describe-port-range
Describe NetworkPolicy port ranges

Kubernetes-commit: 18608386ea5709ec26ed4958ddbba28b6723acee
2024-04-18 10:13:54 +00:00
jwcesign eded7a36b1 upgrade: upgrade dependencies github.com/prometheus/common to the newest version
Signed-off-by: jwcesign <jwcesign@gmail.com>

Kubernetes-commit: f0aa62bc96d6e734249adfa3e094a52e45c8fb6d
2024-04-17 18:15:27 +08:00
Kubernetes Publisher 426055bedd Merge pull request #124174 from dims/update-x/net-for-CVE-2023-45288
Update x/net for CVE-2023-45288

Kubernetes-commit: d9c54f69d4bb7ae1bb655e1a2a50297d615025b5
2024-04-04 04:30:48 +00:00
Davanum Srinivas 0140ee6944 Update x/net for CVE-2023-45288
Signed-off-by: Davanum Srinivas <davanum@gmail.com>

Kubernetes-commit: 99fac38d2864e6bc9bb7cd1743d658caa1360c0c
2024-04-03 16:37:18 -04:00
Dr. Stefan Schimanski bea8dbbff9 kubectl: fix plugin lookup with positional arguments
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@gmail.com>

Kubernetes-commit: 62d379fa5abd4f109b1f1dfe2112feff03c569b4
2024-03-31 19:44:03 +02:00
Amirsadra Abdollahi 41e94233a1 Fix: correct dryRunStratergy typo in kubectl expose cmd
Kubernetes-commit: 041337648938dee4229a4147a0239527b3689082
2024-03-25 18:58:35 +03:30
Kubernetes Publisher 31199ade16 sync: update go.mod 2024-03-18 12:49:13 +00:00
rmiki 3e85d33843 [ja]fix typo in "kubectl config delete-context -h"
Kubernetes-commit: 6229729e86775febdb99b45d03be2b4026f00846
2024-03-13 01:21:01 +09:00
Kubernetes Publisher eb98199dbe Merge pull request #123758 from liggitt/protobump
[CVE-2024-24786] Bump github.com/golang/protobuf v1.5.4, google.golang.org/protobuf v1.33.0

Kubernetes-commit: a5f5f44157c49fdfb6384862c7cb34c2ddbd4cce
2024-03-06 18:27:58 +00:00
Jordan Liggitt 64300085bb Bump github.com/golang/protobuf v1.5.4, google.golang.org/protobuf v1.33.0
Kubernetes-commit: c6673d2346c814ddb4629c569bdc659ffa0c583f
2024-03-06 09:47:28 -05:00
Eduard Voiculescu f8b298459c show warning message only when running kubectl get --watch-only
Kubernetes-commit: a0aa7bf6d18bbeccc48447bb859ffb8fe28da3dc
2024-02-29 13:53:11 -05:00
Siddhant Tibrewal 10fe45a704 Improving Legibility of Kubectl describe configmap by adding new line to output
Kubernetes-commit: cb560a72e0f63a28bdc7b8518f9de89d59f76be5
2024-02-29 18:46:27 +00:00
Ritikaa96 6c2c451048 adding suggested changes
Signed-off-by: Ritikaa96 <ritika@india.nec.com>

Kubernetes-commit: 6f4e60a6b7ce56a5e083330f2b8c2277f4a659f0
2024-02-26 11:05:01 +05:30
Ritikaa96 2f762a69a2 Improving kubectl get output
Adding namespace flag & examples
Signed-off-by: Ritikaa96 <ritika@india.nec.com>

Kubernetes-commit: 22186fafaf79d6eae8375b3d018e181a645a3d31
2024-02-22 14:56:45 +05:30
Stephen Kitt 713b7e79c0 Use canonical json-patch v4 import
The canonical import for json-patch v4 is
gopkg.in/evanphx/json-patch.v4 (see
https://github.com/evanphx/json-patch/blob/master/README.md#get-it for
reference).

Using the v4-specific path should also reduce the risk of unwanted v5
upgrade attempts, because they won't be offered as automated upgrades
by dependency upgrade management tools, and they won't happen through
indirect dependencies (see
https://github.com/kubernetes/kubernetes/pull/120327 for context).

Signed-off-by: Stephen Kitt <skitt@redhat.com>

Kubernetes-commit: 5300466a5c8988b479a151ceb77f49dd00065c83
2024-02-16 13:57:24 +01:00
Stephen Kitt 6b5d9dfa70 Update kubectl kustomize to kyaml/v0.17.1, cmd/config/v0.14.1, api/v0.17.2, kustomize/v5.4.2
Signed-off-by: Stephen Kitt <skitt@redhat.com>

Kubernetes-commit: 33c6f6bc65395aa514c9cf17115a1c63564c22e7
2024-05-27 17:42:29 +02:00
Jaime Caamaño Ruiz 9957529f9c Describe NetworkPolicy port ranges
Signed-off-by: Jaime Caamaño Ruiz <jcaamano@redhat.com>

Kubernetes-commit: aa0e47e863293215db794d6cb5978945e76fe3e2
2024-02-15 12:00:47 +00:00
mochizuki875 916a6ea031 Add keep options
Kubernetes-commit: b63fa1300ca99e65cbb8797c0128f3c1c1d1ef9f
2024-02-06 07:19:23 +00:00
Arda Güçlü 64a1fe556b Add new --wait-for-creation flag in kubectl wait command
kubectl wait command errors out when the waited resource does not exist.
But we need to provide a way to the users about intentionally also waiting for
the creation of resources.

This PR introduces a new flag to cover waiting for the creation of resources
with preserving the default behavior.

Kubernetes-commit: e24b9a022f3b1e97ea538c9754d4d38f119f275e
2024-01-26 15:53:55 +03:00
Yihao Wang 9a6ad3e08e Fix typo in i18n usage examples
Kubernetes-commit: e9c30951051b66bb5050d0d5bf622d4ef7a4481c
2024-01-17 13:12:21 +13:00
lowang-bh 733ee4d85e show pod Status as phase Failed or Succeeded if it has deletionTimestamp
Signed-off-by: lowang-bh <lhui_wang@163.com>

fix according to comments
Signed-off-by: lowang-bh <lhui_wang@163.com>

Kubernetes-commit: 4bd3274f433cc37bde2cff5875d61108cc97a7d2
2023-11-25 21:01:41 +08:00
carlory 7f19a8d4f7 fix unusable secret manifest for type docker-registry
Kubernetes-commit: c12e12bd89570979efd7798a3a809228d36e7ec3
2023-07-26 18:08:01 +08:00
Oldřich Jedlička 1d05cd7a4e Fix editor launch with Windows cmd.exe when KUBE_EDITOR has spaces
Kubernetes-commit: df71672e5798960d0c6b4fa730aa7ac12991aef5
2022-08-29 22:13:25 +02:00
Claudiu Belu 0ee0d225f2 Replaces path.Operation with filepath.Operation (staging)
The path module has a few different functions:
Clean, Split, Join, Ext, Dir, Base, IsAbs. These functions do not
take into account the OS-specific path separator, meaning that they
won't behave as intended on Windows.

For example, Dir is supposed to return all but the last element of the
path. For the path "C:\some\dir\somewhere", it is supposed to return
"C:\some\dir\", however, it returns ".".

Instead of these functions, the ones in filepath should be used instead.

Kubernetes-commit: 856bb5c8f266f5276f1a576f47be622d7cb384e7
2022-06-15 15:17:24 +03:00
210 changed files with 12136 additions and 2242 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
KnVerey
natasha41575
mpuckett159
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 // import "k8s.io/kubectl"
package kubectl

127
go.mod
View File

@ -2,106 +2,93 @@
module k8s.io/kubectl
go 1.22.0
go 1.24.0
godebug default=go1.24
require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/chai2010/gettext-go v1.0.2
github.com/daviddengcn/go-colortext v1.0.0
github.com/distribution/reference v0.5.0
github.com/evanphx/json-patch v4.12.0+incompatible
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d
github.com/distribution/reference v0.6.0
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f
github.com/fatih/camelcase v1.0.0
github.com/fvbommel/sortorder v1.1.0
github.com/go-openapi/jsonreference v0.20.2
github.com/google/gnostic-models v0.6.8
github.com/google/go-cmp v0.6.0
github.com/jonboulle/clockwork v0.2.2
github.com/google/gnostic-models v0.6.9
github.com/google/go-cmp v0.7.0
github.com/jonboulle/clockwork v0.5.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.0.0-20221205130635-1aeaba878587
github.com/onsi/ginkgo/v2 v2.15.0
github.com/onsi/gomega v1.31.0
github.com/pkg/errors v0.9.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/russross/blackfriday/v2 v2.1.0
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
golang.org/x/sys v0.17.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.0.0-20240305044759-dd2e75089b33
k8s.io/apimachinery v0.0.0-20240305011844-67cb3a878cd3
k8s.io/cli-runtime v0.0.0-20240301215537-eeedba799671
k8s.io/client-go v0.0.0-20240305045158-64334495a6f0
k8s.io/component-base v0.0.0-20240301210028-15d726cdca18
k8s.io/component-helpers v0.0.0-20240301210226-e6e24ac471b0
k8s.io/klog/v2 v2.120.1
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340
k8s.io/metrics v0.0.0-20240301215215-36af2eaa1e6d
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3
sigs.k8s.io/structured-merge-diff/v4 v4.4.1
sigs.k8s.io/yaml v1.3.0
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
golang.org/x/sys v0.31.0
gopkg.in/evanphx/json-patch.v4 v4.12.0
k8s.io/api v0.0.0-20250612195650-7efafe3627c8
k8s.io/apimachinery v0.0.0-20250612195403-e0270fe44c97
k8s.io/cli-runtime v0.0.0-20250612204029-ea98d716c955
k8s.io/client-go v0.0.0-20250612200049-4e82e684120e
k8s.io/component-base v0.0.0-20250612201519-d0c00e6471f7
k8s.io/component-helpers v0.0.0-20250612201654-2b90e129ba7a
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
k8s.io/metrics v0.0.0-20250612203843-e8073a5e5ba0
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3
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/v4 v4.7.0
sigs.k8s.io/yaml v1.4.0
)
require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
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.11.0 // indirect
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // 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/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/btree v1.1.3 // 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.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // 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
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/moby/spdystream v0.2.0 // 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.2 // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // 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/x448/float16 v0.8.4 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // 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/tools v0.26.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
)
replace (
k8s.io/api => k8s.io/api v0.0.0-20240305044759-dd2e75089b33
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20240305011844-67cb3a878cd3
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20240301215537-eeedba799671
k8s.io/client-go => k8s.io/client-go v0.0.0-20240305045158-64334495a6f0
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20240301205840-f8417dff616b
k8s.io/component-base => k8s.io/component-base v0.0.0-20240301210028-15d726cdca18
k8s.io/component-helpers => k8s.io/component-helpers v0.0.0-20240301210226-e6e24ac471b0
k8s.io/metrics => k8s.io/metrics v0.0.0-20240301215215-36af2eaa1e6d
sigs.k8s.io/kustomize/api v0.19.0 // indirect
)

312
go.sum
View File

@ -1,109 +1,68 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
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/daviddengcn/go-colortext v1.0.0 h1:ANqDyC0ys6qCSvuEK7l3g5RaehL/Xck9EX8ATG8oKsE=
github.com/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
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.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
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/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
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/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.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A=
github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE=
github.com/golangplus/testing v1.0.0 h1:+ZeeiKZENNOMkTTELoSySazi+XaEhVO0mb+eanrSEUQ=
github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA=
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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
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/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
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/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.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
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=
@ -125,25 +84,26 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
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=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE=
github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
@ -152,163 +112,123 @@ 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
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/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.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
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/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/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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
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/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=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
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=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
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.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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=
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=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20240305044759-dd2e75089b33 h1:t4rX/ZVL/5i5E/Z+kQFnCkqRn4Ni6vf+y7M399XPmSM=
k8s.io/api v0.0.0-20240305044759-dd2e75089b33/go.mod h1:vubRQCvGk3ZRs8VJewbBCTFfaSYNGtDSO4rI+Ur8d0M=
k8s.io/apimachinery v0.0.0-20240305011844-67cb3a878cd3 h1:OQnlxechgbZid21Q0KyffHDuHHZz+G7RTGDA3SIkC+o=
k8s.io/apimachinery v0.0.0-20240305011844-67cb3a878cd3/go.mod h1:qPsrq6INURDMMgqxK78MEuC8GzI1f2oHvfHzg5ZOa6s=
k8s.io/cli-runtime v0.0.0-20240301215537-eeedba799671 h1:kGyGe23DZ0cF3EkTk/+U9/yvFNKLuwiKMMIdFlgXyak=
k8s.io/cli-runtime v0.0.0-20240301215537-eeedba799671/go.mod h1:SzEB7/qbLFBQ32B8zlKrnbU9oxTxKuMjyDsNroi2wnA=
k8s.io/client-go v0.0.0-20240305045158-64334495a6f0 h1:GPra71+5jYpURLYNJrvhcJuBc+WuuXcChI+aUGyi2Kw=
k8s.io/client-go v0.0.0-20240305045158-64334495a6f0/go.mod h1:v+mRdwGXf74Ta3x5vOAqajn7JsX93/+WlQR0KE/EuL8=
k8s.io/component-base v0.0.0-20240301210028-15d726cdca18 h1:kiqSkGxkfImyPIdgBwK6mLoS8yLDijT7wKm35LduYLs=
k8s.io/component-base v0.0.0-20240301210028-15d726cdca18/go.mod h1:ovtVM/EGyY/M89mMKkFZ3tdQREOE2u9pODk7+C6VENQ=
k8s.io/component-helpers v0.0.0-20240301210226-e6e24ac471b0 h1:Zlo5ysZBa3gDwE/zDiinJfH4O6yY43lCGpWRD3dmTgc=
k8s.io/component-helpers v0.0.0-20240301210226-e6e24ac471b0/go.mod h1:MyIpmc2hdnH3LLnX5Rss7MhDdh6tg69DZLU/XsrA3z8=
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/metrics v0.0.0-20240301215215-36af2eaa1e6d h1:YtmAAJAxUsuxeEHjuzjUYq5bQw4l51mwFts54Xf4Z9A=
k8s.io/metrics v0.0.0-20240301215215-36af2eaa1e6d/go.mod h1:OXISdzD18L/I8IAHUq0094fOFSEkzCjenaSRZLEnYRc=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 h1:vq2TtoDcQomhy7OxXLUOzSbHMuMYq0Bjn93cDtJEdKw=
sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3/go.mod h1:/d88dHCvoy7d0AKFT0yytezSGZKjsZBVs9YTkBHSGFk=
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
k8s.io/api v0.0.0-20250612195650-7efafe3627c8 h1:K1AnJQBQTKLy2C/up2YSFuuQ+OBucYGcDCBO2cafjlQ=
k8s.io/api v0.0.0-20250612195650-7efafe3627c8/go.mod h1:+9QbMyXTXctHAXg3fdhJbuZgyzhYgprCn43M5NqoJzw=
k8s.io/apimachinery v0.0.0-20250612195403-e0270fe44c97 h1:h2og30eGCCk1GOEZK6+LNhhlydDcWY3wJaWDIs05xR8=
k8s.io/apimachinery v0.0.0-20250612195403-e0270fe44c97/go.mod h1:EZ7eIfFAwky7ktmG4Pu9XWxBxFG++4dxPDOM0GL3abw=
k8s.io/cli-runtime v0.0.0-20250612204029-ea98d716c955 h1:/vNS33lahptlYENPecDoe4fD8SOE+aGTxP5wozvK7zw=
k8s.io/cli-runtime v0.0.0-20250612204029-ea98d716c955/go.mod h1:Exo7hMRapEHo/QMSGxd1tqaGuZBQpgGZt7Sintr5L/M=
k8s.io/client-go v0.0.0-20250612200049-4e82e684120e h1:xoSxEgTvcAD7YG46B6RN1yZx5KhF0YKNe4SSoY+qSQA=
k8s.io/client-go v0.0.0-20250612200049-4e82e684120e/go.mod h1:hktzpPyrdfB1WrXOvdnDayNSrngzEwWjiwTGqq6Zjns=
k8s.io/component-base v0.0.0-20250612201519-d0c00e6471f7 h1:PmR3IJeL8qbnqdH70lmCLxZjHFr+Cbz5v6VY6ZFlMsI=
k8s.io/component-base v0.0.0-20250612201519-d0c00e6471f7/go.mod h1:eMJvxKozNu3AbHhH6mWUJbzNhElacCbAilLeMjxIW5k=
k8s.io/component-helpers v0.0.0-20250612201654-2b90e129ba7a h1:AccUaO5Y8Z/rRivu4l0eqZbocGbxHGqiuo19dc0vcPw=
k8s.io/component-helpers v0.0.0-20250612201654-2b90e129ba7a/go.mod h1:5Grn35PpLsSHt+WUrQbXI2QN85eBCWnH5nx4fGBbYYU=
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-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
k8s.io/metrics v0.0.0-20250612203843-e8073a5e5ba0 h1:Eo70T+FEfbC83+3nBRAqcUNQf/YnGlkCYj+c1q+lldY=
k8s.io/metrics v0.0.0-20250612203843-e8073a5e5ba0/go.mod h1:wyXjSOSPspEM73pO1WXNVAafLtPfWHMnRPgVrX57niY=
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-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.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 v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
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/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
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

@ -21,8 +21,8 @@ import (
"fmt"
"io"
jsonpatch "github.com/evanphx/json-patch"
"github.com/spf13/cobra"
jsonpatch "gopkg.in/evanphx/json-patch.v4"
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/api/meta"

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.NewString("", "wide", "name")
supportedOutputTypes := sets.New[string]("", "wide", "name")
if !supportedOutputTypes.Has(o.Output) {
return fmt.Errorf("--output %v is not available", o.Output)
}
supportedSortTypes := sets.NewString("", "name", "kind")
supportedSortTypes := sets.New[string]("", "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.NewString(resource.Verbs...).HasAll(o.Verbs...) {
if len(o.Verbs) > 0 && !sets.New[string](resource.Verbs...).HasAll(o.Verbs...) {
continue
}
// filter to resources that belong to the specified categories
if len(o.Categories) > 0 && !sets.NewString(resource.Categories...).HasAll(o.Categories...) {
if len(o.Categories) > 0 && !sets.New[string](resource.Categories...).HasAll(o.Categories...) {
continue
}
resources = append(resources, groupResource{

View File

@ -43,7 +43,7 @@ import (
"k8s.io/client-go/util/csaupgrade"
"k8s.io/component-base/version"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/cmd/delete"
cmddelete "k8s.io/kubectl/pkg/cmd/delete"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
@ -61,7 +61,7 @@ type ApplyFlags struct {
RecordFlags *genericclioptions.RecordFlags
PrintFlags *genericclioptions.PrintFlags
DeleteFlags *delete.DeleteFlags
DeleteFlags *cmddelete.DeleteFlags
FieldManager string
Selector string
@ -71,6 +71,7 @@ type ApplyFlags struct {
All bool
Overwrite bool
OpenAPIPatch bool
Subresource string
PruneAllowlist []string
@ -84,7 +85,7 @@ type ApplyOptions struct {
PrintFlags *genericclioptions.PrintFlags
ToPrinter func(string) (printers.ResourcePrinter, error)
DeleteOptions *delete.DeleteOptions
DeleteOptions *cmddelete.DeleteOptions
ServerSideApply bool
ForceConflicts bool
@ -97,6 +98,7 @@ type ApplyOptions struct {
All bool
Overwrite bool
OpenAPIPatch bool
Subresource string
ValidationDirective string
Validator validation.Schema
@ -182,7 +184,7 @@ var ApplySetToolVersion = version.Get().GitVersion
func NewApplyFlags(streams genericiooptions.IOStreams) *ApplyFlags {
return &ApplyFlags{
RecordFlags: genericclioptions.NewRecordFlags(),
DeleteFlags: delete.NewDeleteFlags("The files that contain the configurations to apply."),
DeleteFlags: cmddelete.NewDeleteFlags("The files that contain the configurations to apply."),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Overwrite: true,
@ -235,6 +237,7 @@ func (flags *ApplyFlags) AddFlags(cmd *cobra.Command) {
cmdutil.AddPruningFlags(cmd, &flags.Prune, &flags.PruneAllowlist, &flags.All, &flags.ApplySetRef)
cmd.Flags().BoolVar(&flags.Overwrite, "overwrite", flags.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
cmd.Flags().BoolVar(&flags.OpenAPIPatch, "openapi-patch", flags.OpenAPIPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
cmdutil.AddSubresourceFlags(cmd, &flags.Subresource, "If specified, apply will operate on the subresource of the requested object. Only allowed when using --server-side.")
}
// ToOptions converts from CLI inputs to runtime inputs
@ -356,6 +359,7 @@ func (flags *ApplyFlags) ToOptions(f cmdutil.Factory, cmd *cobra.Command, baseNa
All: flags.All,
Overwrite: flags.Overwrite,
OpenAPIPatch: flags.OpenAPIPatch,
Subresource: flags.Subresource,
Recorder: recorder,
Namespace: namespace,
@ -438,6 +442,9 @@ func (o *ApplyOptions) Validate() error {
}
}
}
if len(o.Subresource) > 0 && !o.ServerSideApply {
return fmt.Errorf("--subresource can only be specified for --server-side")
}
return nil
}
@ -577,13 +584,15 @@ func (o *ApplyOptions) applyOneObject(info *resource.Info) error {
options := metav1.PatchOptions{
Force: &o.ForceConflicts,
}
obj, err := helper.Patch(
info.Namespace,
info.Name,
types.ApplyPatchType,
data,
&options,
)
obj, err := helper.
WithSubresource(o.Subresource).
Patch(
info.Namespace,
info.Name,
types.ApplyPatchType,
data,
&options,
)
if err != nil {
if isIncompatibleServerError(err) {
err = fmt.Errorf("Server-side apply not available on the server: (%v)", err)
@ -681,6 +690,12 @@ See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts`
return cmdutil.AddSourceToErr("creating", info.Source, err)
}
// prune nulls when client-side apply does a create to match what will happen when client-side applying an update.
// do this after CreateApplyAnnotation so the annotation matches what will be persisted on an update apply of the same manifest.
if u, ok := info.Object.(runtime.Unstructured); ok {
pruneNullsFromMap(u.UnstructuredContent())
}
if o.DryRunStrategy != cmdutil.DryRunClient {
// Then create the resource and skip the three-way merge
obj, err := helper.Create(info.Namespace, true, info.Object)
@ -759,6 +774,29 @@ See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts`
return nil
}
func pruneNullsFromMap(data map[string]interface{}) {
for k, v := range data {
if v == nil {
delete(data, k)
} else {
pruneNulls(v)
}
}
}
func pruneNullsFromSlice(data []interface{}) {
for _, v := range data {
pruneNulls(v)
}
}
func pruneNulls(v interface{}) {
switch v := v.(type) {
case map[string]interface{}:
pruneNullsFromMap(v)
case []interface{}:
pruneNullsFromSlice(v)
}
}
// Saves the last-applied-configuration annotation in a separate SSA field manager
// to prevent it from being dropped by users who have transitioned to SSA.
//

View File

@ -25,6 +25,7 @@ import (
"net/http"
"os"
"path/filepath"
"slices"
"strings"
"testing"
"time"
@ -59,8 +60,7 @@ import (
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/openapi"
utilpointer "k8s.io/utils/pointer"
"k8s.io/utils/strings/slices"
"k8s.io/utils/ptr"
"sigs.k8s.io/yaml"
)
@ -2087,6 +2087,9 @@ func TestForceApply(t *testing.T) {
"post": 1,
}
// Set the patch retry back off period to something low, so the test can run more quickly
patchRetryBackOffPeriod = 1 * time.Millisecond
for _, testingOpenAPISchema := range testingOpenAPISchemas {
for _, openAPIFeatureToggle := range applyFeatureToggles {
@ -2112,7 +2115,7 @@ func TestForceApply(t *testing.T) {
var bodyRC io.ReadCloser
if isScaledDownToZero {
rcObj := readReplicationControllerFromFile(t, filenameRC)
rcObj.Spec.Replicas = utilpointer.Int32Ptr(0)
rcObj.Spec.Replicas = ptr.To[int32](0)
rcBytes, err := runtime.Encode(codec, rcObj)
if err != nil {
t.Fatal(err)
@ -2602,7 +2605,6 @@ 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
@ -2636,7 +2638,6 @@ 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
@ -2671,7 +2672,6 @@ 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,7 +2706,6 @@ 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
@ -2869,7 +2868,6 @@ 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
@ -3087,7 +3085,6 @@ 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
@ -3429,7 +3426,7 @@ func TestApplySetDryRun(t *testing.T) {
cmd.Run(cmd, []string{})
})
assert.Equal(t, "replicationcontroller/test-rc serverside-applied (server dry run)\n", outbuff.String())
assert.Equal(t, len(serverSideData), 1, "unexpected creation")
assert.Len(t, serverSideData, 1, "unexpected creation")
require.Nil(t, serverSideData[pathSecret], "secret was created")
})
@ -3446,7 +3443,7 @@ func TestApplySetDryRun(t *testing.T) {
cmd.Run(cmd, []string{})
})
assert.Equal(t, "replicationcontroller/test-rc configured (dry run)\n", outbuff.String())
assert.Equal(t, len(serverSideData), 1, "unexpected creation")
assert.Len(t, serverSideData, 1, "unexpected creation")
require.Nil(t, serverSideData[pathSecret], "secret was created")
})
}

View File

@ -17,13 +17,12 @@ limitations under the License.
package apply
import (
"context"
"encoding/json"
"fmt"
"io"
"time"
"github.com/pkg/errors"
"github.com/jonboulle/clockwork"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@ -49,8 +48,6 @@ import (
const (
// maxPatchRetry is the maximum number of conflicts retry for during a patch operation before returning failure
maxPatchRetry = 5
// backOffPeriod is the period to back off when apply patch results in error.
backOffPeriod = 1 * time.Second
// how many times we can retry before back off
triesBeforeBackOff = 1
// groupVersionKindExtensionKey is the key used to lookup the
@ -59,7 +56,10 @@ const (
groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
)
var createPatchErrFormat = "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
// 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"
// Patcher defines options to patch OpenAPI objects.
type Patcher struct {
@ -118,13 +118,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, errors.Wrapf(err, "serializing current configuration from:\n%v\nfor:", obj)
return nil, nil, fmt.Errorf("serializing current configuration from:\n%v\nfor: %w", obj, err)
}
// Retrieve the original configuration of the object from the annotation.
original, err := util.GetOriginalConfiguration(obj)
if err != nil {
return nil, nil, errors.Wrapf(err, "retrieving original configuration from:\n%v\nfor:", obj)
return nil, nil, fmt.Errorf("retrieving original configuration from:\n%v\nfor: %w", obj, err)
}
var patchType types.PatchType
@ -176,17 +176,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, errors.Wrapf(err, createPatchErrFormat, original, modified, current)
return nil, nil, fmt.Errorf(createPatchErrFormat, original, modified, current, err)
}
} else {
if !runtime.IsNotRegisteredError(err) {
return nil, nil, errors.Wrapf(err, "getting instance of versioned object for %v:", p.Mapping.GroupVersionKind)
return nil, nil, fmt.Errorf("getting instance of versioned object for %v: %w", p.Mapping.GroupVersionKind, err)
}
patchType = types.MergePatchType
patch, err = p.buildMergePatch(original, modified, current)
if err != nil {
return nil, nil, errors.Wrapf(err, createPatchErrFormat, original, modified, current)
return nil, nil, fmt.Errorf(createPatchErrFormat, original, modified, current, err)
}
}
}
@ -198,7 +198,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, errors.Wrap(err, "Failed to insert resourceVersion in patch")
return nil, nil, fmt.Errorf("failed to insert resourceVersion in patch: %w", err)
}
}
@ -363,7 +363,7 @@ func (p *Patcher) Patch(current runtime.Object, modified []byte, source, namespa
}
for i := 1; i <= p.Retries && apierrors.IsConflict(err); i++ {
if i > triesBeforeBackOff {
p.BackOff.Sleep(backOffPeriod)
p.BackOff.Sleep(patchRetryBackOffPeriod)
}
current, getErr = p.Helper.Get(namespace, name)
if getErr != nil {
@ -386,7 +386,7 @@ func (p *Patcher) deleteAndCreate(original runtime.Object, modified []byte, name
return modified, nil, err
}
// TODO: use wait
if err := wait.PollImmediate(1*time.Second, p.Timeout, func() (bool, error) {
if err := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, p.Timeout, true, func(ctx context.Context) (bool, error) {
if _, err := p.Helper.Get(namespace, name); !apierrors.IsNotFound(err) {
return false, err
}

View File

@ -184,7 +184,9 @@ func createExecutor(url *url.URL, config *restclient.Config) (remotecommand.Exec
if err != nil {
return nil, err
}
exec, err = remotecommand.NewFallbackExecutor(websocketExec, exec, httpstream.IsUpgradeFailure)
exec, err = remotecommand.NewFallbackExecutor(websocketExec, exec, func(err error) bool {
return httpstream.IsUpgradeFailure(err) || httpstream.IsHTTPSProxyError(err)
})
if err != nil {
return nil, err
}
@ -204,7 +206,7 @@ func (o *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []s
o.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return cmdutil.UsageErrorf(cmd, err.Error())
return cmdutil.UsageErrorf(cmd, "%s", err.Error())
}
o.Builder = f.NewBuilder
@ -305,6 +307,7 @@ 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,6 +242,7 @@ func TestAttach(t *testing.T) {
pod *corev1.Pod
remoteAttachErr bool
expectedErr string
expectedErrOut []string
}{
{
name: "pod attach",
@ -251,6 +252,10 @@ 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",
@ -305,10 +310,11 @@ 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: genericiooptions.NewTestIOStreamsDiscard(),
IOStreams: streams,
},
Attach: remoteAttach,
GetPodTimeout: 1000,
@ -349,6 +355,14 @@ 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

@ -83,9 +83,8 @@ var (
# Check to see if I can list deployments in my current namespace
kubectl auth can-i list deployments.apps
# Check to see if service account "foo" of namespace "dev" can list pods
# in the namespace "prod".
# You must be allowed to use impersonation for the global option "--as".
# Check to see if service account "foo" of namespace "dev" can list pods in the namespace "prod"
# You must be allowed to use impersonation for the global option "--as"
kubectl auth can-i list pods --as=system:serviceaccount:dev:foo -n prod
# Check to see if I can do everything in my current namespace ("*" means all)
@ -100,13 +99,16 @@ var (
# Check to see if I can access the URL /logs/
kubectl auth can-i get /logs/
# Check to see if I can approve certificates.k8s.io
kubectl auth can-i approve certificates.k8s.io
# List all allowed actions in namespace "foo"
kubectl auth can-i --list --namespace=foo`)
resourceVerbs = sets.NewString("get", "list", "watch", "create", "update", "patch", "delete", "deletecollection", "use", "bind", "impersonate", "*")
nonResourceURLVerbs = sets.NewString("get", "put", "post", "head", "options", "delete", "patch", "*")
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", "*")
// holds all the server-supported resources that cannot be discovered by clients. i.e. users and groups for the impersonate verb
nonStandardResourceNames = sets.NewString("users", "groups")
nonStandardResourceNames = sets.New[string]("users", "groups")
)
// NewCmdCanI returns an initialized Command for 'auth can-i' sub command
@ -183,7 +185,7 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
default:
errString := "you must specify two arguments: verb resource or verb resource/resourceName."
usageString := "See 'kubectl auth can-i -h' for help and examples."
return errors.New(fmt.Sprintf("%s\n%s", errString, usageString))
return fmt.Errorf("%s\n%s", errString, usageString)
}
}

View File

@ -161,7 +161,7 @@ func TestRunAccessCheck(t *testing.T) {
test.serverErr
}),
}
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}, ContentType: runtime.ContentTypeJSON}}
if err := test.o.Complete(tf, test.args); err != nil {
t.Errorf("%s: %v", test.name, err)
@ -196,6 +196,7 @@ func TestRunAccessList(t *testing.T) {
" [/version] [] [get]\n"
tf := cmdtesting.NewTestFactory().WithNamespace("test")
tf.ClientConfigVal.ContentType = runtime.ContentTypeJSON
defer tf.Cleanup()
ns := scheme.Codecs.WithoutConversion()

View File

@ -122,16 +122,16 @@ var (
whoAmILong = templates.LongDesc(`
Experimental: Check who you are and your attributes (groups, extra).
This command is helpful to get yourself aware of the current user attributes,
especially when dynamic authentication, e.g., token webhook, auth proxy, or OIDC provider,
This command is helpful to get yourself aware of the current user attributes,
especially when dynamic authentication, e.g., token webhook, auth proxy, or OIDC provider,
is enabled in the Kubernetes cluster.
`)
whoAmIExample = templates.Examples(`
# Get your subject attributes.
# Get your subject attributes
kubectl auth whoami
# Get your subject attributes in JSON format.
# Get your subject attributes in JSON format
kubectl auth whoami -o json
`)
)
@ -250,7 +250,7 @@ func printTableSelfSubjectAccessReview(obj runtime.Object, out io.Writer) error
}
if len(ui.Extra) > 0 {
for _, k := range sets.StringKeySet(ui.Extra).List() {
for _, k := range sets.List(sets.KeySet(ui.Extra)) {
v := ui.Extra[k]
_, err := fmt.Fprintf(w, "Extra: %s\t%v\n", k, v)
if err != nil {

View File

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

View File

@ -24,13 +24,17 @@ import (
"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"
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"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
@ -43,6 +47,7 @@ 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.`))
@ -78,7 +83,8 @@ type AutoscaleOptions struct {
builder *resource.Builder
fieldManager string
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
HPAClientV1 autoscalingv1client.HorizontalPodAutoscalersGetter
HPAClientV2 autoscalingv2client.HorizontalPodAutoscalersGetter
scaleKindResolver scale.ScaleKindResolver
genericiooptions.IOStreams
@ -157,7 +163,8 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
if err != nil {
return err
}
o.HPAClient = kubeClient.AutoscalingV1()
o.HPAClientV2 = kubeClient.AutoscalingV2()
o.HPAClientV1 = kubeClient.AutoscalingV1()
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
@ -186,7 +193,6 @@ func (o *AutoscaleOptions) Validate() error {
return nil
}
// Run performs the execution
func (o *AutoscaleOptions) Run() error {
r := o.builder.
Unstructured().
@ -212,44 +218,19 @@ func (o *AutoscaleOptions) Run() error {
return fmt.Errorf("cannot autoscale a %v: %v", mapping.GroupVersionKind.Kind, 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 o.dryRunStrategy == cmdutil.DryRunClient {
count++
printer, err := o.ToPrinter("created")
if err != nil {
// handles the creation of HorizontalPodAutoscaler objects for both v2 and v1 APIs.
// If v2 API fails, try to create and handle HorizontalPodAutoscaler using v1 API
hpaV2 := o.createHorizontalPodAutoscalerV2(info.Name, mapping)
if err := o.handleHPA(hpaV2); err != nil {
klog.V(1).Infof("Encountered an error with the v2 HorizontalPodAutoscaler: %v. "+
"Falling back to try the v1 HorizontalPodAutoscaler", err)
hpaV1 := o.createHorizontalPodAutoscalerV1(info.Name, mapping)
if err := o.handleHPA(hpaV1); 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++
printer, err := o.ToPrinter("autoscaled")
if err != nil {
return err
}
return printer.PrintObj(actualHPA, o.Out)
return nil
})
if err != nil {
return err
@ -260,7 +241,96 @@ func (o *AutoscaleOptions) Run() error {
return nil
}
func (o *AutoscaleOptions) createHorizontalPodAutoscaler(refName string, mapping *meta.RESTMapping) *autoscalingv1.HorizontalPodAutoscaler {
// 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 {
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
}
if o.CPUPercent >= 0 {
scaler.Spec.Metrics = []autoscalingv2.MetricSpec{
{
Type: autoscalingv2.ResourceMetricSourceType,
Resource: &autoscalingv2.ResourceMetricSource{
Name: corev1.ResourceCPU,
Target: autoscalingv2.MetricTarget{
Type: autoscalingv2.UtilizationMetricType,
AverageUtilization: &o.CPUPercent,
},
},
},
}
}
return &scaler
}
func (o *AutoscaleOptions) createHorizontalPodAutoscalerV1(refName string, mapping *meta.RESTMapping) *autoscalingv1.HorizontalPodAutoscaler {
name := o.Name
if len(name) == 0 {
name = refName

View File

@ -0,0 +1,572 @@
/*
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 autoscale
import (
"fmt"
"testing"
"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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/utils/ptr"
)
type validateTestCase struct {
name string
options *AutoscaleOptions
expectedError error
}
func TestAutoscaleValidate(t *testing.T) {
tests := []validateTestCase{
{
name: "valid options",
options: &AutoscaleOptions{
Max: 10,
Min: 1,
},
expectedError: nil,
},
{
name: "max less than 1",
options: &AutoscaleOptions{
Max: 0,
Min: 1,
},
expectedError: fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: 0"),
},
{
name: "min greater than max",
options: &AutoscaleOptions{
Max: 1,
Min: 2,
},
expectedError: fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: 1, min: 2"),
},
{
name: "zero min replicas",
options: &AutoscaleOptions{
Max: 5,
Min: 0,
},
expectedError: nil,
},
{
name: "negative min replicas",
options: &AutoscaleOptions{
Max: 5,
Min: -2,
},
expectedError: nil,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
errorGot := tc.options.Validate()
assert.Equal(t, tc.expectedError, errorGot)
})
}
}
type createHorizontalPodAutoscalerTestCase struct {
name string
options *AutoscaleOptions
refName string
mapping *meta.RESTMapping
expectedHPAV2 *autoscalingv2.HorizontalPodAutoscaler
expectedHPAV1 *autoscalingv1.HorizontalPodAutoscaler
}
func TestCreateHorizontalPodAutoscalerV2(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",
},
},
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)),
},
},
},
},
},
},
},
}
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{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name",
},
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-1",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(10),
TargetCPUUtilizationPercentage: 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",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-2",
},
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-2",
},
MinReplicas: nil,
MaxReplicas: int32(10),
TargetCPUUtilizationPercentage: 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",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-3",
},
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "deployment-3",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(-1),
TargetCPUUtilizationPercentage: 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",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-name-4",
},
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv1.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",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "replicaset-hpa",
},
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "ReplicaSet",
Name: "frontend",
},
MinReplicas: ptr.To(int32(1)),
MaxReplicas: int32(5),
TargetCPUUtilizationPercentage: 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",
},
},
expectedHPAV1: &autoscalingv1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "statefulset-hpa",
},
Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: "web",
},
MinReplicas: ptr.To(int32(2)),
MaxReplicas: int32(8),
TargetCPUUtilizationPercentage: ptr.To(int32(60)),
},
},
},
}
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)
})
}
}

View File

@ -33,7 +33,6 @@ import (
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
ct "github.com/daviddengcn/go-colortext"
"github.com/spf13/cobra"
)
@ -156,12 +155,8 @@ func (o *ClusterInfoOptions) Run() error {
}
func printService(out io.Writer, name, link string) {
ct.ChangeColor(ct.Green, false, ct.None, false)
fmt.Fprint(out, name)
ct.ResetColor()
fmt.Fprint(out, " is running at ")
ct.ChangeColor(ct.Yellow, false, ct.None, false)
fmt.Fprint(out, link)
ct.ResetColor()
fmt.Fprintln(out, "")
}

View File

@ -22,6 +22,7 @@ import (
"io"
"os"
"path"
"path/filepath"
"time"
"github.com/spf13/cobra"
@ -118,8 +119,8 @@ func setupOutputWriter(dir string, defaultWriter io.Writer, filename string, fil
if len(dir) == 0 || dir == "-" {
return defaultWriter
}
fullFile := path.Join(dir, filename) + fileExtension
parent := path.Dir(fullFile)
fullFile := filepath.Join(dir, filename) + fileExtension
parent := filepath.Dir(fullFile)
cmdutil.CheckErr(os.MkdirAll(parent, 0755))
file, err := os.Create(fullFile)

View File

@ -18,7 +18,7 @@ package clusterinfo
import (
"os"
"path"
"path/filepath"
"testing"
"k8s.io/cli-runtime/pkg/genericiooptions"
@ -60,7 +60,7 @@ func TestSetupOutputWriterFile(t *testing.T) {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
fullPath := path.Join(dir, file) + extension
fullPath := filepath.Join(dir, file) + extension
defer os.RemoveAll(dir)
_, _, buf, _ := genericiooptions.NewTestIOStreams()

View File

@ -73,6 +73,7 @@ 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"
@ -82,8 +83,6 @@ import (
"k8s.io/kubectl/pkg/cmd/kustomize"
)
const kubectlCmdHeaders = "KUBECTL_COMMAND_HEADERS"
type KubectlOptions struct {
PluginHandler PluginHandler
Arguments []string
@ -136,31 +135,29 @@ func NewDefaultKubectlCommandWithArgs(o KubectlOptions) *cobra.Command {
case "help", cobra.ShellCompRequestCmd, cobra.ShellCompNoDescRequestCmd:
// Don't search for a plugin
default:
if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, false); err != nil {
if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, 1); err != nil {
fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err)
os.Exit(1)
}
}
} else if err == nil {
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
}
// 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, true); 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)
}
}
}
@ -259,7 +256,7 @@ func (h *DefaultPluginHandler) Execute(executablePath string, cmdArgs, environme
// HandlePluginCommand receives a pluginHandler and command-line arguments and attempts to find
// a plugin executable on the PATH that satisfies the given arguments.
func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, exactMatch bool) error {
func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, minArgs int) error {
var remainingArgs []string // all "non-flag" arguments
for _, arg := range cmdArgs {
if strings.HasPrefix(arg, "-") {
@ -279,13 +276,14 @@ func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, exactMat
for len(remainingArgs) > 0 {
path, found := pluginHandler.Lookup(strings.Join(remainingArgs, "-"))
if !found {
if exactMatch {
// if exactMatch is true, we shouldn't continue searching with shorter names.
remainingArgs = remainingArgs[:len(remainingArgs)-1]
if len(remainingArgs) < minArgs {
// we shouldn't continue searching with shorter names.
// this is especially for not searching kubectl-create plugin
// when kubectl-create-foo plugin is not found.
break
}
remainingArgs = remainingArgs[:len(remainingArgs)-1]
continue
}
@ -360,6 +358,11 @@ 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)
@ -382,6 +385,8 @@ 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{
{
@ -433,7 +438,7 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
proxyCmd,
cp.NewCmdCp(f, o.IOStreams),
auth.NewCmdAuth(f, o.IOStreams),
debug.NewCmdDebug(f, o.IOStreams),
debugCmd,
events.NewCmdEvents(f, o.IOStreams),
},
},
@ -479,7 +484,7 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
registerCompletionFuncForGlobalFlags(cmds, f)
cmds.AddCommand(alpha)
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), o.IOStreams))
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), o.IOStreams))
cmds.AddCommand(plugin.NewCmdPlugin(o.IOStreams))
cmds.AddCommand(version.NewCmdVersion(f, o.IOStreams))
cmds.AddCommand(apiresources.NewCmdAPIVersions(f, o.IOStreams))
@ -489,6 +494,15 @@ 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
}
@ -506,12 +520,9 @@ 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 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
}
if cmdutil.CmdHeaders.IsDisabled() {
klog.V(5).Infoln("kubectl command headers turned off")
return
}
klog.V(5).Infoln("kubectl command headers turned on")
crt := &genericclioptions.CommandHeaderRoundTripper{}
@ -565,3 +576,29 @@ 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,6 +29,7 @@ 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) {
@ -196,6 +197,18 @@ func TestKubectlCommandHandlesPlugins(t *testing.T) {
expectPlugin: "plugin/testdata/kubectl-foo",
expectPluginArgs: []string{"--bar"},
},
{
name: "test that a plugin executable is found based on command args with positional argument",
args: []string{"kubectl", "foo", "positional", "--bar"},
expectPlugin: "plugin/testdata/kubectl-foo",
expectPluginArgs: []string{"positional", "--bar"},
},
{
name: "test that an allowed subcommand plugin executable is found based on command args with positional argument",
args: []string{"kubectl", "create", "foo", "positional", "--bar"},
expectPlugin: "plugin/testdata/kubectl-create-foo",
expectPluginArgs: []string{"positional", "--bar"},
},
{
name: "test that a plugin does not execute over an existing command by the same name",
args: []string{"kubectl", "version", "--client=true"},
@ -330,6 +343,7 @@ func (h *testPluginHandler) Lookup(filename string) (string, bool) {
for _, p := range plugins {
filenameWithSuportedPrefix = fmt.Sprintf("%s-%s", prefix, filename)
if p.Name() == filenameWithSuportedPrefix {
h.lookupErr = nil
return fmt.Sprintf("%s/%s", h.pluginsDirectory, p.Name()), true
}
}
@ -368,10 +382,6 @@ 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 {
@ -381,7 +391,7 @@ func TestKubectlCommandHeadersHooks(t *testing.T) {
if kubeConfigFlags.WrapConfigFn != nil {
t.Fatal("expected initial nil WrapConfigFn")
}
t.Setenv(kubectlCmdHeaders, testCase.envVar)
t.Setenv(string(cmdutil.CmdHeaders), testCase.envVar)
addCmdHeaderHooks(cmds, kubeConfigFlags)
// Valdidate whether the hooks were added.
if testCase.addsHooks && kubeConfigFlags.WrapConfigFn == nil {

View File

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/client-go/tools/clientcmd"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
@ -31,7 +32,7 @@ import (
)
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
func NewCmdConfig(pathOptions *clientcmd.PathOptions, streams genericiooptions.IOStreams) *cobra.Command {
func NewCmdConfig(restClientGetter genericclioptions.RESTClientGetter, pathOptions *clientcmd.PathOptions, streams genericiooptions.IOStreams) *cobra.Command {
if len(pathOptions.ExplicitFileFlag) == 0 {
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
}
@ -58,7 +59,7 @@ func NewCmdConfig(pathOptions *clientcmd.PathOptions, streams genericiooptions.I
cmd.AddCommand(NewCmdConfigView(streams, pathOptions))
cmd.AddCommand(NewCmdConfigSetCluster(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSetCredentials(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSetContext(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSetContext(restClientGetter, streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSet(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigUnset(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigCurrentContext(streams.Out, pathOptions))

View File

@ -19,7 +19,7 @@ package config
import (
"fmt"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"testing"
@ -30,6 +30,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
utiltesting "k8s.io/client-go/util/testing"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)
@ -68,7 +69,6 @@ func Example_view() {
// name: federal-context
// current-context: federal-context
// kind: Config
// preferences: {}
// users:
// - name: red-user
// user:
@ -415,7 +415,7 @@ func TestEmptyTokenAndCertAllowed(t *testing.T) {
defer utiltesting.CloseAndRemove(t, fakeCertFile)
expectedConfig := newRedFederalCowHammerConfig()
authInfo := clientcmdapi.NewAuthInfo()
authInfo.ClientCertificate = path.Base(fakeCertFile.Name())
authInfo.ClientCertificate = filepath.Base(fakeCertFile.Name())
expectedConfig.AuthInfos["another-user"] = authInfo
test := configCommandTest{
@ -660,7 +660,7 @@ func TestCAClearsInsecure(t *testing.T) {
clusterInfoWithInsecure.InsecureSkipTLSVerify = true
clusterInfoWithCA := clientcmdapi.NewCluster()
clusterInfoWithCA.CertificateAuthority = path.Base(fakeCAFile.Name())
clusterInfoWithCA.CertificateAuthority = filepath.Base(fakeCAFile.Name())
startingConfig := newRedFederalCowHammerConfig()
startingConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
@ -948,8 +948,11 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
argsToUse = append(argsToUse, args...)
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), streams)
cmd := NewCmdConfig(tf, clientcmd.NewDefaultPathOptions(), streams)
// "context" is a global flag, inherited from base kubectl command in the real world
cmd.PersistentFlags().String("context", "", "The name of the kubeconfig context to use")
cmd.SetArgs(argsToUse)

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.NewString("", "name")
supportedOutputTypes := sets.New[string]("", "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.StringKeySet(mapValueOptions))
nextPart := findNameStep(individualParts[currPartIndex:], sets.KeySet(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.String) string {
func findNameStep(parts []string, typeOptions sets.Set[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.String) int {
func findKnownValue(parts []string, valueOptions sets.Set[string]) int {
for i := range parts {
if valueOptions.Has(parts[i]) {
return i

View File

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
cliflag "k8s.io/component-base/cli/flag"
@ -53,7 +54,7 @@ var (
)
// NewCmdConfigSetContext returns a Command instance for 'config set-context' sub command
func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
func NewCmdConfigSetContext(restClientGetter genericclioptions.RESTClientGetter, out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
options := &setContextOptions{configAccess: configAccess}
cmd := &cobra.Command{
@ -79,6 +80,12 @@ func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess)
cmd.Flags().Var(&options.cluster, clientcmd.FlagClusterName, clientcmd.FlagClusterName+" for the context entry in kubeconfig")
cmd.Flags().Var(&options.authInfo, clientcmd.FlagAuthInfoName, clientcmd.FlagAuthInfoName+" for the context entry in kubeconfig")
cmd.Flags().Var(&options.namespace, clientcmd.FlagNamespace, clientcmd.FlagNamespace+" for the context entry in kubeconfig")
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
"namespace",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completion.CompGetResource(cmdutil.NewFactory(restClientGetter), "namespace", toComplete), cobra.ShellCompDirectiveNoFileComp
},
))
return cmd
}

View File

@ -21,10 +21,10 @@ import (
"os"
"testing"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
utiltesting "k8s.io/client-go/util/testing"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
)
type setContextTest struct {
@ -122,7 +122,11 @@ func (test setContextTest) run(t *testing.T) {
pathOptions.GlobalFile = fakeKubeFile.Name()
pathOptions.EnvVar = ""
buf := bytes.NewBuffer([]byte{})
cmd := NewCmdConfigSetContext(buf, pathOptions)
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
cmd := NewCmdConfigSetContext(tf, buf, pathOptions)
cmd.SetArgs(test.args)
cmd.Flags().Parse(test.flags)
if err := cmd.Execute(); err != nil {

View File

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

View File

@ -18,12 +18,13 @@ package cp
import (
"archive/tar"
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"time"
"github.com/spf13/cobra"
@ -267,8 +268,8 @@ func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
options := &exec.ExecOptions{
StreamOptions: exec.StreamOptions{
IOStreams: genericiooptions.IOStreams{
Out: bytes.NewBuffer([]byte{}),
ErrOut: bytes.NewBuffer([]byte{}),
Out: io.Discard,
ErrOut: io.Discard,
},
Namespace: dest.PodNamespace,
@ -279,7 +280,21 @@ func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
Executor: &exec.DefaultRemoteExecutor{},
}
return o.execute(options)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
done := make(chan error)
go func() {
done <- o.execute(options)
}()
select {
case <-ctx.Done():
return ctx.Err()
case err := <-done:
return err
}
}
func (o *CopyOptions) copyToPod(src, dest fileSpec, options *exec.ExecOptions) error {
@ -295,6 +310,10 @@ func (o *CopyOptions) copyToPod(src, dest fileSpec, options *exec.ExecOptions) e
// If no error, dest.File was found to be a directory.
// Copy specified src into it
destFile = destFile.Join(srcFile.Base())
} else if errors.Is(err, context.DeadlineExceeded) {
// we haven't decided destination is directory or not because context timeout is exceeded.
// That's why, we should shortcut the process in here.
return err
}
go func(src localPath, dest remotePath, writer io.WriteCloser) {

View File

@ -988,6 +988,6 @@ func cmpFileData(t *testing.T, filePath, data string) {
type testWriter testing.T
func (t *testWriter) Write(p []byte) (n int, err error) {
t.Logf(string(p))
t.Log(string(p))
return len(p), nil
}

View File

@ -109,12 +109,6 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobr
Long: createLong,
Example: createExample,
Run: func(cmd *cobra.Command, args []string) {
if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
ioStreams.ErrOut.Write([]byte("Error: must specify one of -f and -k\n\n"))
defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
defaultRunFunc(cmd, args)
return
}
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunCreate(f, cmd))
@ -159,8 +153,12 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobr
return cmd
}
// Validate makes sure there is no discrepency in command options
// Validate makes sure there is no discrepancy in command options
func (o *CreateOptions) Validate() error {
if err := o.FilenameOptions.RequireFilenameOrKustomize(); err != nil {
return err
}
if len(o.Raw) > 0 {
if o.EditBeforeCreate {
return fmt.Errorf("--raw and --edit are mutually exclusive")

View File

@ -20,7 +20,7 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"unicode/utf8"
@ -320,7 +320,7 @@ func handleConfigMapFromFileSources(configMap *corev1.ConfigMap, fileSources []s
return fmt.Errorf("error listing files in %s: %v", filePath, err)
}
for _, item := range fileList {
itemPath := path.Join(filePath, item.Name())
itemPath := filepath.Join(filePath, item.Name())
if item.Type().IsRegular() {
keyName = item.Name()
err = addKeyFromFileToConfigMap(configMap, keyName, itemPath)

View File

@ -35,6 +35,7 @@ import (
"k8s.io/kubectl/pkg/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
"k8s.io/utils/ptr"
)
var (
@ -261,10 +262,21 @@ func (o *CreateJobOptions) createJobFromCronJob(cronJob *batchv1.CronJob) *batch
// this is ok because we know exactly how we want to be serialized
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: o.Name,
Annotations: annotations,
Labels: cronJob.Spec.JobTemplate.Labels,
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(cronJob, batchv1.SchemeGroupVersion.WithKind("CronJob"))},
Name: o.Name,
Annotations: annotations,
Labels: cronJob.Spec.JobTemplate.Labels,
OwnerReferences: []metav1.OwnerReference{
{
// we are not using metav1.NewControllerRef because it
// sets BlockOwnerDeletion to true which additionally mandates
// cronjobs/finalizer role and not backwards-compatible.
APIVersion: batchv1.SchemeGroupVersion.String(),
Kind: "CronJob",
Name: cronJob.GetName(),
UID: cronJob.GetUID(),
Controller: ptr.To(true),
},
},
},
Spec: cronJob.Spec.JobTemplate.Spec,
}

View File

@ -24,6 +24,7 @@ import (
corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
)
func TestCreateJobValidation(t *testing.T) {
@ -161,9 +162,17 @@ func TestCreateJobFromCronJob(t *testing.T) {
expected: &batchv1.Job{
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
Annotations: map[string]string{"cronjob.kubernetes.io/instantiate": "manual"},
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(cronJob, batchv1.SchemeGroupVersion.WithKind("CronJob"))},
Name: jobName,
Annotations: map[string]string{"cronjob.kubernetes.io/instantiate": "manual"},
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: batchv1.SchemeGroupVersion.String(),
Kind: "CronJob",
Name: cronJob.GetName(),
UID: cronJob.GetUID(),
Controller: ptr.To(true),
},
},
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{

View File

@ -116,7 +116,7 @@ var (
func AddSpecialVerb(verb string, gr schema.GroupResource) {
resources, ok := specialVerbs[verb]
if !ok {
resources = make([]schema.GroupResource, 1)
resources = make([]schema.GroupResource, 0, 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.StringKeySet(groupResourceMapping).List() {
for _, g := range sets.List(sets.KeySet(groupResourceMapping)) {
rule := rbacv1.PolicyRule{}
rule.Verbs = verbs
rule.Resources = groupResourceMapping[g]

View File

@ -684,14 +684,17 @@ 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,
},
}
@ -703,6 +706,16 @@ 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

@ -44,7 +44,7 @@ var (
# Create a role binding for user1, user2, and group1 using the admin cluster role
kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1
# Create a role binding for serviceaccount monitoring:sa-dev using the admin role
# Create a role binding for service account monitoring:sa-dev using the admin role
kubectl create rolebinding admin-binding --role=admin --serviceaccount=monitoring:sa-dev`))
)

View File

@ -20,7 +20,7 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"github.com/spf13/cobra"
@ -349,7 +349,7 @@ func handleSecretFromFileSources(secret *corev1.Secret, fileSources []string) er
return fmt.Errorf("error listing files in %s: %v", filePath, err)
}
for _, item := range fileList {
itemPath := path.Join(filePath, item.Name())
itemPath := filepath.Join(filePath, item.Name())
if item.Type().IsRegular() {
keyName = item.Name()
if err := addKeyFromFileToSecret(secret, keyName, itemPath); err != nil {

View File

@ -21,6 +21,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
@ -58,7 +59,7 @@ var (
kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
# Create a new secret named my-secret from ~/.docker/config.json
kubectl create secret docker-registry my-secret --from-file=.dockerconfigjson=path/to/.docker/config.json`))
kubectl create secret docker-registry my-secret --from-file=path/to/.docker/config.json`))
)
// DockerConfigJSON represents a local docker auth config file
@ -152,7 +153,11 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, ioStreams genericioopti
cmd.Flags().StringVar(&o.Email, "docker-email", o.Email, i18n.T("Email for Docker registry"))
cmd.Flags().StringVar(&o.Server, "docker-server", o.Server, i18n.T("Server location for Docker registry"))
cmd.Flags().BoolVar(&o.AppendHash, "append-hash", o.AppendHash, "Append a hash of the secret to its name.")
cmd.Flags().StringSliceVar(&o.FileSources, "from-file", o.FileSources, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
cmd.Flags().StringSliceVar(&o.FileSources, "from-file", o.FileSources, "Key files can be specified using their file path, "+
"in which case a default name of "+corev1.DockerConfigJsonKey+" will be given to them, "+
"or optionally with a name and file path, in which case the given name will be used. "+
"Specifying a directory will iterate each named file in the directory that is a valid secret key. "+
"For this command, the key should always be "+corev1.DockerConfigJsonKey+".")
cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create")
@ -204,6 +209,11 @@ func (o *CreateSecretDockerRegistryOptions) Complete(f cmdutil.Factory, cmd *cob
return err
}
for i := range o.FileSources {
if !strings.Contains(o.FileSources[i], "=") {
o.FileSources[i] = corev1.DockerConfigJsonKey + "=" + o.FileSources[i]
}
}
return nil
}

View File

@ -17,11 +17,16 @@ limitations under the License.
package create
import (
"encoding/json"
"fmt"
"os"
"testing"
corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericiooptions"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
)
func TestCreateSecretDockerRegistry(t *testing.T) {
@ -183,3 +188,80 @@ func TestCreateSecretDockerRegistry(t *testing.T) {
})
}
}
func TestCreateSecretDockerRegistryFromFile(t *testing.T) {
username, password, email, server := "test-user", "test-password", "test-user@example.org", "https://index.docker.io/v1/"
secretData, err := handleDockerCfgJSONContent(username, password, email, server)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Type: corev1.SecretTypeDockerConfigJson,
Data: map[string][]byte{
corev1.DockerConfigJsonKey: secretData,
},
}
tests := map[string]struct {
withKey bool
expected *corev1.Secret
}{
"create_secret_docker_registry_from_file_with_keyname": {
withKey: true,
expected: secret,
},
"create_secret_docker_registry_from_file_without_keyname": {
withKey: false,
expected: secret,
},
}
// Run all the tests
for name, test := range tests {
t.Run(name, func(t *testing.T) {
tmp, _ := os.MkdirTemp("", "input")
defer func() {
err := os.RemoveAll(tmp)
if err != nil {
t.Fatalf("Failed to teardown: %s", err)
}
}()
dockerCfgFile := tmp + "/dockerconfig.json"
err := os.WriteFile(dockerCfgFile, secretData, 0644)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
ioStreams, _, out, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdCreateSecretDockerRegistry(tf, ioStreams)
args := []string{"foo", "--dry-run=client", "-ojson"}
if test.withKey {
args = append(args, fmt.Sprintf("--from-file=%s=%s", corev1.DockerConfigJsonKey, dockerCfgFile))
} else {
args = append(args, fmt.Sprintf("--from-file=%s", dockerCfgFile))
}
cmd.SetArgs(args)
err = cmd.Execute()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
got := &corev1.Secret{}
err = json.Unmarshal(out.Bytes(), got)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !apiequality.Semantic.DeepEqual(got, test.expected) {
t.Errorf("test %s\n expected:\n%#v\ngot:\n%#v", name, test.expected, got)
}
})
}
}

View File

@ -18,7 +18,7 @@ package create
import (
"os"
"path"
"path/filepath"
"testing"
corev1 "k8s.io/api/core/v1"
@ -197,8 +197,8 @@ func write(path, contents string, t *testing.T) {
}
func writeKeyPair(tmpDirPath, key, cert string, t *testing.T) (keyPath, certPath string) {
keyPath = path.Join(tmpDirPath, "tls.key")
certPath = path.Join(tmpDirPath, "tls.cert")
keyPath = filepath.Join(tmpDirPath, "tls.key")
certPath = filepath.Join(tmpDirPath, "tls.cert")
write(keyPath, key, t)
write(certPath, cert, t)
return

View File

@ -18,6 +18,7 @@ package create
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
@ -399,12 +400,12 @@ func parsePorts(portString string) (int32, intstr.IntOrString, error) {
var targetPort intstr.IntOrString
if portNum, err := strconv.Atoi(portStringSlice[1]); err != nil {
if errs := validation.IsValidPortName(portStringSlice[1]); len(errs) != 0 {
return 0, intstr.FromInt32(0), fmt.Errorf(strings.Join(errs, ","))
return 0, intstr.FromInt32(0), errors.New(strings.Join(errs, ","))
}
targetPort = intstr.FromString(portStringSlice[1])
} else {
if errs := validation.IsValidPortNum(portNum); len(errs) != 0 {
return 0, intstr.FromInt32(0), fmt.Errorf(strings.Join(errs, ","))
return 0, intstr.FromInt32(0), errors.New(strings.Join(errs, ","))
}
targetPort = intstr.FromInt32(int32(portNum))
}

View File

@ -25,6 +25,7 @@ import (
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/rest/fake"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
)
@ -150,3 +151,35 @@ func TestCreateDirectory(t *testing.T) {
t.Errorf("unexpected output: %s", buf.String())
}
}
func TestMissingFilenameError(t *testing.T) {
var errStr string
var exitCode int
cmdutil.BehaviorOnFatal(func(str string, code int) {
if errStr == "" {
errStr = str
exitCode = code
}
})
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
ioStreams, _, buf, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdCreate(tf, ioStreams)
cmd.Run(cmd, []string{})
if buf.Len() > 0 {
t.Errorf("unexpected output: %s", buf.String())
}
if len(errStr) == 0 {
t.Errorf("unexpected non-error")
} else if errStr != "error: must specify one of -f and -k" {
t.Errorf("unexpected error: %s", errStr)
}
if exitCode != 1 {
t.Errorf("unexpected exit code: %d", exitCode)
}
}

View File

@ -19,7 +19,6 @@ package create
import (
"context"
"fmt"
"os"
"strings"
"time"
@ -39,7 +38,7 @@ import (
"k8s.io/kubectl/pkg/util/completion"
"k8s.io/kubectl/pkg/util/templates"
"k8s.io/kubectl/pkg/util/term"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
// TokenOptions is the data required to perform a token request operation.
@ -99,15 +98,10 @@ var (
`)
)
func boundObjectKindToAPIVersions() map[string]string {
kinds := map[string]string{
"Pod": "v1",
"Secret": "v1",
}
if os.Getenv("KUBECTL_NODE_BOUND_TOKENS") == "true" {
kinds["Node"] = "v1"
}
return kinds
var boundObjectKinds = map[string]string{
"Pod": "v1",
"Secret": "v1",
"Node": "v1",
}
func NewTokenOpts(ioStreams genericiooptions.IOStreams) *TokenOptions {
@ -151,7 +145,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.StringKeySet(boundObjectKindToAPIVersions()).List(), ", ")+". "+
"Supported kinds are "+strings.Join(sets.List(sets.KeySet(boundObjectKinds)), ", ")+". "+
"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. "+
@ -228,8 +222,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 := boundObjectKindToAPIVersions()[o.BoundObjectKind]; !ok {
return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.StringKeySet(boundObjectKindToAPIVersions()).List(), ", "))
if _, ok := boundObjectKinds[o.BoundObjectKind]; !ok {
return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.List(sets.KeySet(boundObjectKinds)), ", "))
}
if len(o.BoundObjectName) == 0 {
return fmt.Errorf("--bound-object-name is required if --bound-object-kind is provided")
@ -247,12 +241,12 @@ func (o *TokenOptions) Run() error {
},
}
if o.Duration > 0 {
request.Spec.ExpirationSeconds = pointer.Int64(int64(o.Duration / time.Second))
request.Spec.ExpirationSeconds = ptr.To(int64(o.Duration / time.Second))
}
if len(o.BoundObjectKind) > 0 {
request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{
Kind: o.BoundObjectKind,
APIVersion: boundObjectKindToAPIVersions()[o.BoundObjectKind],
APIVersion: boundObjectKinds[o.BoundObjectKind],
Name: o.BoundObjectName,
UID: types.UID(o.BoundObjectUID),
}

View File

@ -21,13 +21,11 @@ import (
"encoding/json"
"io"
"net/http"
"os"
"reflect"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"k8s.io/utils/pointer"
kjson "sigs.k8s.io/json"
authenticationv1 "k8s.io/api/authentication/v1"
@ -39,6 +37,7 @@ import (
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/utils/ptr"
)
func TestCreateToken(t *testing.T) {
@ -54,8 +53,6 @@ func TestCreateToken(t *testing.T) {
audiences []string
duration time.Duration
enableNodeBindingFeature bool
serverResponseToken string
serverResponseError string
@ -102,8 +99,7 @@ func TestCreateToken(t *testing.T) {
serverResponseToken: "abc",
expectStdout: `apiVersion: authentication.k8s.io/v1
kind: TokenRequest
metadata:
creationTimestamp: null
metadata: {}
spec:
audiences: null
boundObjectRef: null
@ -118,14 +114,13 @@ status:
test: "bad bound object kind",
name: "mysa",
boundObjectKind: "Foo",
expectStderr: `error: supported --bound-object-kind values are Pod, Secret`,
expectStderr: `error: supported --bound-object-kind values are Node, Pod, Secret`,
},
{
test: "bad bound object kind (node feature enabled)",
name: "mysa",
enableNodeBindingFeature: true,
boundObjectKind: "Foo",
expectStderr: `error: supported --bound-object-kind values are Node, Pod, Secret`,
test: "bad bound object kind (node feature enabled)",
name: "mysa",
boundObjectKind: "Foo",
expectStderr: `error: supported --bound-object-kind values are Node, Pod, Secret`,
},
{
test: "missing bound object name",
@ -172,10 +167,9 @@ status:
test: "valid bound object (Node)",
name: "mysa",
enableNodeBindingFeature: true,
boundObjectKind: "Node",
boundObjectName: "mynode",
boundObjectUID: "myuid",
boundObjectKind: "Node",
boundObjectName: "mynode",
boundObjectUID: "myuid",
expectRequestPath: "/api/v1/namespaces/test/serviceaccounts/mysa/token",
expectTokenRequest: &authenticationv1.TokenRequest{
@ -237,7 +231,7 @@ status:
expectTokenRequest: &authenticationv1.TokenRequest{
TypeMeta: metav1.TypeMeta{APIVersion: "authentication.k8s.io/v1", Kind: "TokenRequest"},
Spec: authenticationv1.TokenRequestSpec{
ExpirationSeconds: pointer.Int64(1000),
ExpirationSeconds: ptr.To[int64](1000),
},
},
serverResponseToken: "abc",
@ -367,10 +361,6 @@ status:
if test.duration != 0 {
cmd.Flags().Set("duration", test.duration.String())
}
if test.enableNodeBindingFeature {
os.Setenv("KUBECTL_NODE_BOUND_TOKENS", "true")
defer os.Unsetenv("KUBECTL_NODE_BOUND_TOKENS")
}
cmd.Run(cmd, []string{test.name})
if !reflect.DeepEqual(tokenRequest, test.expectTokenRequest) {

View File

@ -25,8 +25,6 @@ import (
"github.com/distribution/reference"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@ -46,6 +44,7 @@ import (
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/cmd/attach"
"k8s.io/kubectl/pkg/cmd/exec"
"k8s.io/kubectl/pkg/cmd/logs"
@ -56,6 +55,8 @@ import (
"k8s.io/kubectl/pkg/util/interrupt"
"k8s.io/kubectl/pkg/util/templates"
"k8s.io/kubectl/pkg/util/term"
"k8s.io/utils/ptr"
"sigs.k8s.io/yaml"
)
var (
@ -74,6 +75,9 @@ 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(`
@ -111,29 +115,35 @@ type DebugAttachFunc func(ctx context.Context, restClientGetter genericclioption
// DebugOptions holds the options for an invocation of kubectl debug.
type DebugOptions struct {
Args []string
ArgsOnly bool
Attach bool
AttachFunc DebugAttachFunc
Container string
CopyTo string
Replace bool
Env []corev1.EnvVar
Image string
Interactive bool
Namespace string
TargetNames []string
PullPolicy corev1.PullPolicy
Quiet bool
SameNode bool
SetImages map[string]string
ShareProcesses bool
TargetContainer string
TTY bool
Profile string
CustomProfileFile string
CustomProfile *corev1.Container
Applier ProfileApplier
Args []string
ArgsOnly bool
Attach bool
AttachFunc DebugAttachFunc
Container string
CopyTo string
Replace bool
Env []corev1.EnvVar
Image string
Interactive bool
KeepLabels bool
KeepAnnotations bool
KeepLiveness bool
KeepReadiness bool
KeepStartup bool
KeepInitContainers bool
Namespace string
TargetNames []string
PullPolicy corev1.PullPolicy
Quiet bool
SameNode bool
SetImages map[string]string
ShareProcesses bool
TargetContainer string
TTY bool
Profile string
CustomProfileFile string
CustomProfile *corev1.Container
Applier ProfileApplier
explicitNamespace bool
attachChanged bool
@ -151,10 +161,11 @@ type DebugOptions struct {
// NewDebugOptions returns a DebugOptions initialized with default values.
func NewDebugOptions(streams genericiooptions.IOStreams) *DebugOptions {
return &DebugOptions{
Args: []string{},
IOStreams: streams,
TargetNames: []string{},
ShareProcesses: true,
Args: []string{},
IOStreams: streams,
KeepInitContainers: true,
TargetNames: []string{},
ShareProcesses: true,
}
}
@ -189,6 +200,12 @@ func (o *DebugOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&o.Replace, "replace", o.Replace, i18n.T("When used with '--copy-to', delete the original Pod."))
cmd.Flags().StringToString("env", nil, i18n.T("Environment variables to set in the container."))
cmd.Flags().StringVar(&o.Image, "image", o.Image, i18n.T("Container image to use for debug container."))
cmd.Flags().BoolVar(&o.KeepLabels, "keep-labels", o.KeepLabels, i18n.T("If true, keep the original pod labels.(This flag only works when used with '--copy-to')"))
cmd.Flags().BoolVar(&o.KeepAnnotations, "keep-annotations", o.KeepAnnotations, i18n.T("If true, keep the original pod annotations.(This flag only works when used with '--copy-to')"))
cmd.Flags().BoolVar(&o.KeepLiveness, "keep-liveness", o.KeepLiveness, i18n.T("If true, keep the original pod liveness probes.(This flag only works when used with '--copy-to')"))
cmd.Flags().BoolVar(&o.KeepReadiness, "keep-readiness", o.KeepReadiness, i18n.T("If true, keep the original pod readiness probes.(This flag only works when used with '--copy-to')"))
cmd.Flags().BoolVar(&o.KeepStartup, "keep-startup", o.KeepStartup, i18n.T("If true, keep the original startup probes.(This flag only works when used with '--copy-to')"))
cmd.Flags().BoolVar(&o.KeepInitContainers, "keep-init-containers", o.KeepInitContainers, i18n.T("Run the init containers for the pod. Defaults to true.(This flag only works when used with '--copy-to')"))
cmd.Flags().StringToStringVar(&o.SetImages, "set-image", o.SetImages, i18n.T("When used with '--copy-to', a list of name=image pairs for changing container images, similar to how 'kubectl set image' works."))
cmd.Flags().String("image-pull-policy", "", i18n.T("The image pull policy for the container. If left empty, this value will not be specified by the client and defaulted by the server."))
cmd.Flags().BoolVarP(&o.Interactive, "stdin", "i", o.Interactive, i18n.T("Keep stdin open on the container(s) in the pod, even if nothing is attached."))
@ -198,9 +215,7 @@ func (o *DebugOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.TargetContainer, "target", "", i18n.T("When using an ephemeral container, target processes in this container name."))
cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, i18n.T("Allocate a TTY for the debugging container."))
cmd.Flags().StringVar(&o.Profile, "profile", ProfileLegacy, i18n.T(`Options are "legacy", "general", "baseline", "netadmin", "restricted" or "sysadmin".`))
if cmdutil.DebugCustomProfile.IsEnabled() {
cmd.Flags().StringVar(&o.CustomProfileFile, "custom", o.CustomProfileFile, i18n.T("Path to a JSON file containing a partial container spec to customize built-in debug profiles."))
}
cmd.Flags().StringVar(&o.CustomProfileFile, "custom", o.CustomProfileFile, i18n.T("Path to a JSON or YAML file containing a partial container spec to customize built-in debug profiles."))
}
// Complete finishes run-time initialization of debug.DebugOptions.
@ -257,7 +272,15 @@ func (o *DebugOptions) Complete(restClientGetter genericclioptions.RESTClientGet
}
if o.Applier == nil {
applier, err := NewProfileApplier(o.Profile)
kflags := KeepFlags{
Labels: o.KeepLabels,
Annotations: o.KeepAnnotations,
Liveness: o.KeepLiveness,
Readiness: o.KeepReadiness,
Startup: o.KeepStartup,
InitContainers: o.KeepInitContainers,
}
applier, err := NewProfileApplier(o.Profile, kflags)
if err != nil {
return err
}
@ -272,7 +295,10 @@ func (o *DebugOptions) Complete(restClientGetter genericclioptions.RESTClientGet
err = json.Unmarshal(customProfileBytes, &o.CustomProfile)
if err != nil {
return fmt.Errorf("%s does not contain a valid container spec: %w", o.CustomProfileFile, err)
err = yaml.Unmarshal(customProfileBytes, &o.CustomProfile)
if err != nil {
return fmt.Errorf("%s does not contain a valid container spec: %w", o.CustomProfileFile, err)
}
}
}
@ -374,6 +400,11 @@ func (o *DebugOptions) Validate() error {
}
}
// Warning for legacy profile
if o.Profile == ProfileLegacy {
fmt.Fprintln(o.ErrOut, `--profile=legacy is deprecated and will be removed in the future. It is recommended to explicitly specify a profile, for example "--profile=general".`)
}
return nil
}
@ -467,6 +498,8 @@ 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)
@ -583,6 +616,16 @@ 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
@ -596,6 +639,32 @@ 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) {
@ -708,6 +777,7 @@ func (o *DebugOptions) generatePodCopyWithDebugContainer(pod *corev1.Pod) (*core
Name: o.CopyTo,
Namespace: pod.Namespace,
Annotations: pod.Annotations,
Labels: pod.Labels,
},
Spec: *pod.Spec.DeepCopy(),
}
@ -715,7 +785,7 @@ func (o *DebugOptions) generatePodCopyWithDebugContainer(pod *corev1.Pod) (*core
copied.Spec.EphemeralContainers = nil
// change ShareProcessNamespace configuration only when commanded explicitly
if o.shareProcessedChanged {
copied.Spec.ShareProcessNamespace = pointer.Bool(o.ShareProcesses)
copied.Spec.ShareProcessNamespace = ptr.To(o.ShareProcesses)
}
if !o.SameNode {
copied.Spec.NodeName = ""
@ -916,12 +986,12 @@ func (o *DebugOptions) handleAttachPod(ctx context.Context, restClientGetter gen
}
if status.State.Terminated != nil {
klog.V(1).Info("Ephemeral container terminated, falling back to logs")
return logOpts(restClientGetter, pod, opts)
return logOpts(ctx, restClientGetter, pod, opts)
}
if err := opts.Run(); err != nil {
fmt.Fprintf(opts.ErrOut, "warning: couldn't attach to pod/%s, falling back to streaming logs: %v\n", podName, err)
return logOpts(restClientGetter, pod, opts)
return logOpts(ctx, restClientGetter, pod, opts)
}
return nil
}
@ -939,7 +1009,7 @@ func getContainerStatusByName(pod *corev1.Pod, containerName string) *corev1.Con
}
// logOpts logs output from opts to the pods log.
func logOpts(restClientGetter genericclioptions.RESTClientGetter, pod *corev1.Pod, opts *attach.AttachOptions) error {
func logOpts(ctx context.Context, restClientGetter genericclioptions.RESTClientGetter, pod *corev1.Pod, opts *attach.AttachOptions) error {
ctrName, err := opts.GetContainerName(pod)
if err != nil {
return err
@ -950,7 +1020,7 @@ func logOpts(restClientGetter genericclioptions.RESTClientGetter, pod *corev1.Po
return err
}
for _, request := range requests {
if err := logs.DefaultConsumeRequest(request, opts.Out); err != nil {
if err := logs.DefaultConsumeRequest(ctx, request, opts.Out); err != nil {
return err
}
}

View File

@ -22,8 +22,6 @@ import (
"testing"
"time"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/spf13/cobra"
@ -32,7 +30,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericiooptions"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
func TestGenerateDebugContainer(t *testing.T) {
@ -287,11 +285,11 @@ func TestGenerateDebugContainer(t *testing.T) {
ImagePullPolicy: corev1.PullIfNotPresent,
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -332,25 +330,31 @@ func TestGenerateDebugContainer(t *testing.T) {
ImagePullPolicy: corev1.PullIfNotPresent,
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
suffixCounter = 0
if tc.pod == nil {
tc.pod = &corev1.Pod{}
var err error
kflags := KeepFlags{
Labels: tc.opts.KeepLabels,
Annotations: tc.opts.KeepAnnotations,
Liveness: tc.opts.KeepLiveness,
Readiness: tc.opts.KeepReadiness,
Startup: tc.opts.KeepStartup,
InitContainers: tc.opts.KeepInitContainers,
}
applier, err := NewProfileApplier(tc.opts.Profile)
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile, kflags)
if err != nil {
t.Fatalf("failed to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.Applier = applier
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
suffixCounter = 0
if tc.pod == nil {
tc.pod = &corev1.Pod{}
}
_, debugContainer, err := tc.opts.generateDebugContainer(tc.pod)
if err != nil {
@ -426,6 +430,9 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
havePod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "target",
Labels: map[string]string{
"app": "business",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@ -792,13 +799,63 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
},
},
},
{
name: "pod with probes",
opts: &DebugOptions{
CopyTo: "debugger",
Container: "debugger",
Image: "busybox",
KeepLiveness: true,
KeepReadiness: true,
KeepStartup: true,
PullPolicy: corev1.PullIfNotPresent,
Profile: ProfileLegacy,
},
havePod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "target",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "business",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
wantPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "debugger",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "business",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{
Name: "debugger",
Image: "busybox",
ImagePullPolicy: corev1.PullIfNotPresent,
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
},
},
},
},
},
{
name: "pod with init containers",
opts: &DebugOptions{
CopyTo: "debugger",
Image: "busybox",
PullPolicy: corev1.PullIfNotPresent,
Profile: ProfileLegacy,
CopyTo: "debugger",
Image: "busybox",
KeepInitContainers: true,
PullPolicy: corev1.PullIfNotPresent,
Profile: ProfileLegacy,
},
havePod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
@ -937,7 +994,7 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -1182,7 +1239,7 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
},
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -1220,7 +1277,7 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
ImagePullPolicy: corev1.PullIfNotPresent,
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -1260,7 +1317,7 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
ImagePullPolicy: corev1.PullIfNotPresent,
},
},
ShareProcessNamespace: pointer.Bool(false),
ShareProcessNamespace: ptr.To(false),
},
},
},
@ -1297,16 +1354,16 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
Image: "busybox",
ImagePullPolicy: corev1.PullIfNotPresent,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -1349,14 +1406,22 @@ func TestGeneratePodCopyWithDebugContainer(t *testing.T) {
},
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
var err error
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile)
kflags := KeepFlags{
Labels: tc.opts.KeepLabels,
Annotations: tc.opts.KeepAnnotations,
Liveness: tc.opts.KeepLiveness,
Readiness: tc.opts.KeepReadiness,
Startup: tc.opts.KeepStartup,
InitContainers: tc.opts.KeepInitContainers,
}
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile, kflags)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
@ -1668,11 +1733,11 @@ func TestGenerateNodeDebugPod(t *testing.T) {
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
VolumeMounts: nil,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -1739,7 +1804,15 @@ func TestGenerateNodeDebugPod(t *testing.T) {
} {
t.Run(tc.name, func(t *testing.T) {
var err error
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile)
kflags := KeepFlags{
Labels: tc.opts.KeepLabels,
Annotations: tc.opts.KeepAnnotations,
Liveness: tc.opts.KeepLiveness,
Readiness: tc.opts.KeepReadiness,
Startup: tc.opts.KeepStartup,
InitContainers: tc.opts.KeepInitContainers,
}
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile, kflags)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
@ -1783,7 +1856,7 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -1802,7 +1875,7 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -1855,11 +1928,11 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -1983,7 +2056,7 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
},
},
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
},
},
},
@ -2013,23 +2086,29 @@ func TestGenerateNodeDebugPodCustomProfile(t *testing.T) {
} {
t.Run(tc.name, func(t *testing.T) {
cmdtesting.WithAlphaEnvs([]cmdutil.FeatureGate{cmdutil.DebugCustomProfile}, t, func(t *testing.T) {
var err error
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
var err error
kflags := KeepFlags{
Labels: tc.opts.KeepLabels,
Annotations: tc.opts.KeepAnnotations,
Liveness: tc.opts.KeepLiveness,
Readiness: tc.opts.KeepReadiness,
Startup: tc.opts.KeepStartup,
InitContainers: tc.opts.KeepInitContainers,
}
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile, kflags)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
pod, err := tc.opts.generateNodeDebugPod(tc.node)
if err != nil {
t.Fatalf("Fail to generate node debug pod: %v", err)
}
tc.expected.Name = pod.Name
if diff := cmp.Diff(tc.expected, pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
pod, err := tc.opts.generateNodeDebugPod(tc.node)
if err != nil {
t.Fatalf("Fail to generate node debug pod: %v", err)
}
tc.expected.Name = pod.Name
if diff := cmp.Diff(tc.expected, pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
}
}
@ -2062,7 +2141,7 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -2079,7 +2158,7 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -2090,7 +2169,7 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
HostNetwork: false,
HostPID: false,
Volumes: nil,
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -2115,7 +2194,7 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -2132,8 +2211,8 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
RunAsNonRoot: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -2148,7 +2227,7 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
HostNetwork: false,
HostPID: false,
Volumes: nil,
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -2173,7 +2252,7 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -2190,8 +2269,8 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
RunAsNonRoot: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -2206,30 +2285,36 @@ func TestGenerateCopyDebugPodCustomProfile(t *testing.T) {
HostNetwork: false,
HostPID: false,
Volumes: nil,
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
cmdtesting.WithAlphaEnvs([]cmdutil.FeatureGate{cmdutil.DebugCustomProfile}, t, func(t *testing.T) {
var err error
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
var err error
kflags := KeepFlags{
Labels: tc.opts.KeepLabels,
Annotations: tc.opts.KeepAnnotations,
Liveness: tc.opts.KeepLiveness,
Readiness: tc.opts.KeepReadiness,
Startup: tc.opts.KeepStartup,
InitContainers: tc.opts.KeepInitContainers,
}
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile, kflags)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
pod, dc, err := tc.opts.generatePodCopyWithDebugContainer(tc.copyPod)
if err != nil {
t.Fatalf("Fail to generate node debug pod: %v", err)
}
tc.expected.Spec.Containers[0].Name = dc
if diff := cmp.Diff(tc.expected, pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
pod, dc, err := tc.opts.generatePodCopyWithDebugContainer(tc.copyPod)
if err != nil {
t.Fatalf("Fail to generate node debug pod: %v", err)
}
tc.expected.Spec.Containers[0].Name = dc
if diff := cmp.Diff(tc.expected, pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
}
}
@ -2262,7 +2347,7 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -2281,7 +2366,7 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -2317,7 +2402,7 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -2336,8 +2421,8 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
RunAsNonRoot: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -2377,7 +2462,7 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: pointer.Bool(false),
RunAsNonRoot: ptr.To(false),
},
},
},
@ -2396,8 +2481,8 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
Stdin: true,
TTY: false,
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
RunAsNonRoot: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
RunAsNonRoot: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
@ -2419,23 +2504,29 @@ func TestGenerateEphemeralDebugPodCustomProfile(t *testing.T) {
} {
t.Run(tc.name, func(t *testing.T) {
cmdtesting.WithAlphaEnvs([]cmdutil.FeatureGate{cmdutil.DebugCustomProfile}, t, func(t *testing.T) {
var err error
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
var err error
kflags := KeepFlags{
Labels: tc.opts.KeepLabels,
Annotations: tc.opts.KeepAnnotations,
Liveness: tc.opts.KeepLiveness,
Readiness: tc.opts.KeepReadiness,
Startup: tc.opts.KeepStartup,
InitContainers: tc.opts.KeepInitContainers,
}
tc.opts.Applier, err = NewProfileApplier(tc.opts.Profile, kflags)
if err != nil {
t.Fatalf("Fail to create profile applier: %s: %v", tc.opts.Profile, err)
}
tc.opts.IOStreams = genericiooptions.NewTestIOStreamsDiscard()
pod, ec, err := tc.opts.generateDebugContainer(tc.copyPod)
if err != nil {
t.Fatalf("Fail to generate node debug pod: %v", err)
}
tc.expected.Spec.EphemeralContainers[0].Name = ec.Name
if diff := cmp.Diff(tc.expected, pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
pod, ec, err := tc.opts.generateDebugContainer(tc.copyPod)
if err != nil {
t.Fatalf("Fail to generate node debug pod: %v", err)
}
tc.expected.Spec.EphemeralContainers[0].Name = ec.Name
if diff := cmp.Diff(tc.expected, pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
}
}
@ -2486,94 +2577,101 @@ func TestCompleteAndValidate(t *testing.T) {
name: "Set image pull policy",
args: "--image=busybox --image-pull-policy=Always mypod",
wantOpts: &DebugOptions{
Args: []string{},
Image: "busybox",
Namespace: "test",
PullPolicy: corev1.PullPolicy("Always"),
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
Args: []string{},
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
PullPolicy: corev1.PullPolicy("Always"),
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
},
},
{
name: "Multiple targets",
args: "--image=busybox mypod1 mypod2",
wantOpts: &DebugOptions{
Args: []string{},
Image: "busybox",
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod1", "mypod2"},
Args: []string{},
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod1", "mypod2"},
},
},
{
name: "Arguments with dash",
args: "--image=busybox mypod1 mypod2 -- echo 1 2",
wantOpts: &DebugOptions{
Args: []string{"echo", "1", "2"},
Image: "busybox",
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod1", "mypod2"},
Args: []string{"echo", "1", "2"},
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod1", "mypod2"},
},
},
{
name: "Interactive no attach",
args: "-ti --image=busybox --attach=false mypod",
wantOpts: &DebugOptions{
Args: []string{},
Attach: false,
Image: "busybox",
Interactive: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
Args: []string{},
Attach: false,
Image: "busybox",
KeepInitContainers: true,
Interactive: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
},
},
{
name: "Set environment variables",
args: "--image=busybox --env=FOO=BAR mypod",
wantOpts: &DebugOptions{
Args: []string{},
Env: []corev1.EnvVar{{Name: "FOO", Value: "BAR"}},
Image: "busybox",
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
Args: []string{},
Env: []corev1.EnvVar{{Name: "FOO", Value: "BAR"}},
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
},
},
{
name: "Ephemeral container: interactive session minimal args",
args: "mypod -it --image=busybox",
wantOpts: &DebugOptions{
Args: []string{},
Attach: true,
Image: "busybox",
Interactive: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
Args: []string{},
Attach: true,
Image: "busybox",
Interactive: true,
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
},
},
{
name: "Ephemeral container: non-interactive debugger with image and name",
args: "--image=myproj/debug-tools --image-pull-policy=Always -c debugger mypod",
wantOpts: &DebugOptions{
Args: []string{},
Container: "debugger",
Image: "myproj/debug-tools",
Namespace: "test",
PullPolicy: corev1.PullPolicy("Always"),
Profile: ProfileLegacy,
ShareProcesses: true,
TargetNames: []string{"mypod"},
Args: []string{},
Container: "debugger",
Image: "myproj/debug-tools",
KeepInitContainers: true,
Namespace: "test",
PullPolicy: corev1.PullPolicy("Always"),
Profile: ProfileLegacy,
ShareProcesses: true,
TargetNames: []string{"mypod"},
},
},
{
@ -2605,67 +2703,72 @@ func TestCompleteAndValidate(t *testing.T) {
name: "Pod copy: interactive debug container minimal args",
args: "mypod -it --image=busybox --copy-to=my-debugger",
wantOpts: &DebugOptions{
Args: []string{},
Attach: true,
CopyTo: "my-debugger",
Image: "busybox",
Interactive: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
Args: []string{},
Attach: true,
CopyTo: "my-debugger",
Image: "busybox",
Interactive: true,
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
},
},
{
name: "Pod copy: non-interactive with debug container, image name and command",
args: "mypod --image=busybox --container=my-container --copy-to=my-debugger -- sleep 1d",
wantOpts: &DebugOptions{
Args: []string{"sleep", "1d"},
Container: "my-container",
CopyTo: "my-debugger",
Image: "busybox",
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
Args: []string{"sleep", "1d"},
Container: "my-container",
CopyTo: "my-debugger",
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
},
},
{
name: "Pod copy: explicit attach",
args: "mypod --image=busybox --copy-to=my-debugger --attach -- sleep 1d",
wantOpts: &DebugOptions{
Args: []string{"sleep", "1d"},
Attach: true,
CopyTo: "my-debugger",
Image: "busybox",
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
Args: []string{"sleep", "1d"},
Attach: true,
CopyTo: "my-debugger",
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
},
},
{
name: "Pod copy: replace single image of existing container",
args: "mypod --image=busybox --container=my-container --copy-to=my-debugger",
wantOpts: &DebugOptions{
Args: []string{},
Container: "my-container",
CopyTo: "my-debugger",
Image: "busybox",
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
Args: []string{},
Container: "my-container",
CopyTo: "my-debugger",
Image: "busybox",
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
},
},
{
name: "Pod copy: mutate existing container images",
args: "mypod --set-image=*=busybox,app=app-debugger --copy-to=my-debugger",
wantOpts: &DebugOptions{
Args: []string{},
CopyTo: "my-debugger",
Namespace: "test",
Args: []string{},
CopyTo: "my-debugger",
KeepInitContainers: true,
Namespace: "test",
SetImages: map[string]string{
"*": "busybox",
"app": "app-debugger",
@ -2679,12 +2782,13 @@ func TestCompleteAndValidate(t *testing.T) {
name: "Pod copy: add container and also mutate images",
args: "mypod -it --copy-to=my-debugger --image=debian --set-image=app=app:debug,sidecar=sidecar:debug",
wantOpts: &DebugOptions{
Args: []string{},
Attach: true,
CopyTo: "my-debugger",
Image: "debian",
Interactive: true,
Namespace: "test",
Args: []string{},
Attach: true,
CopyTo: "my-debugger",
Image: "debian",
Interactive: true,
KeepInitContainers: true,
Namespace: "test",
SetImages: map[string]string{
"app": "app:debug",
"sidecar": "sidecar:debug",
@ -2699,16 +2803,39 @@ func TestCompleteAndValidate(t *testing.T) {
name: "Pod copy: change command",
args: "mypod -it --copy-to=my-debugger --container=mycontainer -- sh",
wantOpts: &DebugOptions{
Attach: true,
Args: []string{"sh"},
Container: "mycontainer",
CopyTo: "my-debugger",
Interactive: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
Attach: true,
Args: []string{"sh"},
Container: "mycontainer",
CopyTo: "my-debugger",
Interactive: true,
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
},
},
{
name: "Pod copy: change keep options from defaults",
args: "mypod -it --image=busybox --copy-to=my-debugger --keep-labels=true --keep-annotations=true --keep-liveness=true --keep-readiness=true --keep-startup=true --keep-init-containers=false",
wantOpts: &DebugOptions{
Args: []string{},
Attach: true,
CopyTo: "my-debugger",
Image: "busybox",
Interactive: true,
KeepLabels: true,
KeepAnnotations: true,
KeepLiveness: true,
KeepReadiness: true,
KeepStartup: true,
KeepInitContainers: false,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"mypod"},
TTY: true,
},
},
{
@ -2740,15 +2867,16 @@ func TestCompleteAndValidate(t *testing.T) {
name: "Node: interactive session minimal args",
args: "node/mynode -it --image=busybox",
wantOpts: &DebugOptions{
Args: []string{},
Attach: true,
Image: "busybox",
Interactive: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"node/mynode"},
TTY: true,
Args: []string{},
Attach: true,
Image: "busybox",
Interactive: true,
KeepInitContainers: true,
Namespace: "test",
ShareProcesses: true,
Profile: ProfileLegacy,
TargetNames: []string{"node/mynode"},
TTY: true,
},
},
{

View File

@ -22,7 +22,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubectl/pkg/util/podutils"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
type debugStyle int
@ -64,54 +64,91 @@ type ProfileApplier interface {
}
// NewProfileApplier returns a new Options for the given profile name.
func NewProfileApplier(profile string) (ProfileApplier, error) {
func NewProfileApplier(profile string, kflags KeepFlags) (ProfileApplier, error) {
switch profile {
case ProfileLegacy:
return &legacyProfile{}, nil
return &legacyProfile{kflags}, nil
case ProfileGeneral:
return &generalProfile{}, nil
return &generalProfile{kflags}, nil
case ProfileBaseline:
return &baselineProfile{}, nil
return &baselineProfile{kflags}, nil
case ProfileRestricted:
return &restrictedProfile{}, nil
return &restrictedProfile{kflags}, nil
case ProfileNetadmin:
return &netadminProfile{}, nil
return &netadminProfile{kflags}, nil
case ProfileSysadmin:
return &sysadminProfile{}, nil
return &sysadminProfile{kflags}, nil
}
return nil, fmt.Errorf("unknown profile: %s", profile)
}
type legacyProfile struct {
KeepFlags
}
type generalProfile struct {
KeepFlags
}
type baselineProfile struct {
KeepFlags
}
type restrictedProfile struct {
KeepFlags
}
type netadminProfile struct {
KeepFlags
}
type sysadminProfile struct {
KeepFlags
}
func (p *legacyProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
switch target.(type) {
case *corev1.Pod:
// do nothing to the copied pod
return nil
case *corev1.Node:
mountRootPartition(pod, containerName)
useHostNamespaces(pod)
return nil
default:
return fmt.Errorf("the %s profile doesn't support objects of type %T", ProfileLegacy, target)
// KeepFlags holds the flag set that determine which fields to keep in the copy pod.
type KeepFlags struct {
Labels bool
Annotations bool
Liveness bool
Readiness bool
Startup bool
InitContainers bool
}
// RemoveLabels removes labels from the pod.
func (kflags KeepFlags) RemoveLabels(p *corev1.Pod) {
if !kflags.Labels {
p.Labels = nil
}
}
// RemoveAnnotations remove annotations from the pod.
func (kflags KeepFlags) RemoveAnnotations(p *corev1.Pod) {
if !kflags.Annotations {
p.Annotations = nil
}
}
// RemoveProbes remove probes from all containers of the pod.
func (kflags KeepFlags) RemoveProbes(p *corev1.Pod) {
for i := range p.Spec.Containers {
if !kflags.Liveness {
p.Spec.Containers[i].LivenessProbe = nil
}
if !kflags.Readiness {
p.Spec.Containers[i].ReadinessProbe = nil
}
if !kflags.Startup {
p.Spec.Containers[i].StartupProbe = nil
}
}
}
// RemoveInitContainers remove initContainers from the pod.
func (kflags KeepFlags) RemoveInitContainers(p *corev1.Pod) {
if !kflags.InitContainers {
p.Spec.InitContainers = nil
}
}
@ -130,10 +167,32 @@ func getDebugStyle(pod *corev1.Pod, target runtime.Object) (debugStyle, error) {
return unsupported, fmt.Errorf("objects of type %T are not supported", target)
}
func (p *legacyProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
style, err := getDebugStyle(pod, target)
if err != nil {
return fmt.Errorf("legacy profile: %w", err)
}
switch style {
case node:
mountRootPartition(pod, containerName)
useHostNamespaces(pod)
case podCopy:
p.Labels = false
p.RemoveLabels(pod)
case ephemeral:
// no additional modifications needed
}
return nil
}
func (p *generalProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
style, err := getDebugStyle(pod, target)
if err != nil {
return fmt.Errorf("general profile: %s", err)
return fmt.Errorf("general profile: %w", err)
}
switch style {
@ -143,7 +202,10 @@ func (p *generalProfile) Apply(pod *corev1.Pod, containerName string, target run
useHostNamespaces(pod)
case podCopy:
removeLabelsAndProbes(pod)
p.RemoveLabels(pod)
p.RemoveAnnotations(pod)
p.RemoveProbes(pod)
p.RemoveInitContainers(pod)
allowProcessTracing(pod, containerName)
shareProcessNamespace(pod)
@ -157,14 +219,17 @@ func (p *generalProfile) Apply(pod *corev1.Pod, containerName string, target run
func (p *baselineProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
style, err := getDebugStyle(pod, target)
if err != nil {
return fmt.Errorf("baseline profile: %s", err)
return fmt.Errorf("baseline profile: %w", err)
}
clearSecurityContext(pod, containerName)
switch style {
case podCopy:
removeLabelsAndProbes(pod)
p.RemoveLabels(pod)
p.RemoveAnnotations(pod)
p.RemoveProbes(pod)
p.RemoveInitContainers(pod)
shareProcessNamespace(pod)
case ephemeral, node:
@ -177,7 +242,7 @@ func (p *baselineProfile) Apply(pod *corev1.Pod, containerName string, target ru
func (p *restrictedProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
style, err := getDebugStyle(pod, target)
if err != nil {
return fmt.Errorf("restricted profile: %s", err)
return fmt.Errorf("restricted profile: %w", err)
}
clearSecurityContext(pod, containerName)
@ -188,6 +253,10 @@ func (p *restrictedProfile) Apply(pod *corev1.Pod, containerName string, target
switch style {
case podCopy:
p.RemoveLabels(pod)
p.RemoveAnnotations(pod)
p.RemoveProbes(pod)
p.RemoveInitContainers(pod)
shareProcessNamespace(pod)
case ephemeral, node:
@ -200,7 +269,7 @@ func (p *restrictedProfile) Apply(pod *corev1.Pod, containerName string, target
func (p *netadminProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
style, err := getDebugStyle(pod, target)
if err != nil {
return fmt.Errorf("netadmin profile: %s", err)
return fmt.Errorf("netadmin profile: %w", err)
}
allowNetadminCapability(pod, containerName)
@ -210,6 +279,10 @@ func (p *netadminProfile) Apply(pod *corev1.Pod, containerName string, target ru
useHostNamespaces(pod)
case podCopy:
p.RemoveLabels(pod)
p.RemoveAnnotations(pod)
p.RemoveProbes(pod)
p.RemoveInitContainers(pod)
shareProcessNamespace(pod)
case ephemeral:
@ -222,7 +295,7 @@ func (p *netadminProfile) Apply(pod *corev1.Pod, containerName string, target ru
func (p *sysadminProfile) Apply(pod *corev1.Pod, containerName string, target runtime.Object) error {
style, err := getDebugStyle(pod, target)
if err != nil {
return fmt.Errorf("sysadmin profile: %s", err)
return fmt.Errorf("sysadmin profile: %w", err)
}
setPrivileged(pod, containerName)
@ -234,7 +307,12 @@ func (p *sysadminProfile) Apply(pod *corev1.Pod, containerName string, target ru
case podCopy:
// to mimic general, default and baseline
p.RemoveLabels(pod)
p.RemoveAnnotations(pod)
p.RemoveProbes(pod)
p.RemoveInitContainers(pod)
shareProcessNamespace(pod)
case ephemeral:
// no additional modifications needed
}
@ -242,17 +320,6 @@ func (p *sysadminProfile) Apply(pod *corev1.Pod, containerName string, target ru
return nil
}
// removeLabelsAndProbes removes labels from the pod and remove probes
// from all containers of the pod.
func removeLabelsAndProbes(p *corev1.Pod) {
p.Labels = nil
for i := range p.Spec.Containers {
p.Spec.Containers[i].LivenessProbe = nil
p.Spec.Containers[i].ReadinessProbe = nil
p.Spec.Containers[i].StartupProbe = nil
}
}
// mountRootPartition mounts the host's root path at "/host" in the container.
func mountRootPartition(p *corev1.Pod, containerName string) {
const volumeName = "host-root"
@ -286,7 +353,7 @@ func useHostNamespaces(p *corev1.Pod) {
// process namespace.
func shareProcessNamespace(p *corev1.Pod) {
if p.Spec.ShareProcessNamespace == nil {
p.Spec.ShareProcessNamespace = pointer.Bool(true)
p.Spec.ShareProcessNamespace = ptr.To(true)
}
}
@ -310,7 +377,7 @@ func setPrivileged(p *corev1.Pod, containerName string) {
if c.SecurityContext == nil {
c.SecurityContext = &corev1.SecurityContext{}
}
c.SecurityContext.Privileged = pointer.Bool(true)
c.SecurityContext.Privileged = ptr.To(true)
return false
})
}
@ -324,7 +391,7 @@ func disallowRoot(p *corev1.Pod, containerName string) {
if c.SecurityContext == nil {
c.SecurityContext = &corev1.SecurityContext{}
}
c.SecurityContext.RunAsNonRoot = pointer.Bool(true)
c.SecurityContext.RunAsNonRoot = ptr.To(true)
return false
})
}
@ -389,7 +456,7 @@ func disallowPrivilegeEscalation(p *corev1.Pod, containerName string) {
if c.SecurityContext == nil {
c.SecurityContext = &corev1.SecurityContext{}
}
c.SecurityContext.AllowPrivilegeEscalation = pointer.Bool(false)
c.SecurityContext.AllowPrivilegeEscalation = ptr.To(false)
return false
})
}

View File

@ -25,7 +25,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
var testNode = &corev1.Node{
@ -34,6 +34,203 @@ var testNode = &corev1.Node{
},
}
func TestLegacyProfile(t *testing.T) {
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "pod"},
Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
{
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Name: "dbg", Image: "dbgimage",
},
},
}},
}
tests := map[string]struct {
pod *corev1.Pod
containerName string
target runtime.Object
expectPod *corev1.Pod
expectErr bool
}{
"bad inputs results in error": {
pod: nil,
containerName: "dbg",
target: runtime.Object(nil),
expectErr: true,
},
"debug by ephemeral container": {
pod: pod,
containerName: "dbg",
target: pod,
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "pod"},
Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
{
EphemeralContainerCommon: corev1.EphemeralContainerCommon{Name: "dbg", Image: "dbgimage"},
},
}},
},
},
"debug by pod copy": {
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"NET_ADMIN"},
},
},
},
},
},
},
containerName: "dbg",
target: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"NET_ADMIN"},
},
},
},
},
},
},
},
"debug by node": {
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "pod"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"NET_ADMIN"},
},
},
},
},
},
},
containerName: "dbg",
target: testNode,
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "pod"},
Spec: corev1.PodSpec{
HostNetwork: true,
HostPID: true,
HostIPC: true,
Containers: []corev1.Container{
{
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"NET_ADMIN"},
},
},
VolumeMounts: []corev1.VolumeMount{
{
MountPath: "/host",
Name: "host-root",
},
},
},
},
Volumes: []corev1.Volume{
{
Name: "host-root",
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{Path: "/"},
},
},
},
},
},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
applier := &legacyProfile{KeepFlags{InitContainers: true}}
err := applier.Apply(test.pod, test.containerName, test.target)
if (err != nil) != test.expectErr {
t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
}
if err != nil {
return
}
if diff := cmp.Diff(test.expectPod, test.pod); diff != "" {
t.Error("unexpected diff in generated object: (-want +got):\n", diff)
}
})
}
}
func TestGeneralProfile(t *testing.T) {
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "pod"},
@ -81,10 +278,25 @@ func TestGeneralProfile(t *testing.T) {
},
"debug by pod copy": {
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{
Name: "dbg",
Image: "dbgimage",
@ -99,16 +311,32 @@ func TestGeneralProfile(t *testing.T) {
},
containerName: "dbg",
target: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
@ -121,7 +349,7 @@ func TestGeneralProfile(t *testing.T) {
},
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -169,7 +397,8 @@ func TestGeneralProfile(t *testing.T) {
for name, test := range tests {
t.Run(name, func(t *testing.T) {
err := (&generalProfile{}).Apply(test.pod, test.containerName, test.target)
applier := &generalProfile{KeepFlags{InitContainers: true}}
err := applier.Apply(test.pod, test.containerName, test.target)
if (err != nil) != test.expectErr {
t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
}
@ -230,27 +459,58 @@ func TestBaselineProfile(t *testing.T) {
},
"debug by pod copy": {
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{Name: "dbg", Image: "dbgimage"},
},
},
},
containerName: "dbg",
target: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
@ -288,7 +548,8 @@ func TestBaselineProfile(t *testing.T) {
for name, test := range tests {
t.Run(name, func(t *testing.T) {
err := (&baselineProfile{}).Apply(test.pod, test.containerName, test.target)
applier := &baselineProfile{KeepFlags{InitContainers: true}}
err := applier.Apply(test.pod, test.containerName, test.target)
if (err != nil) != test.expectErr {
t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
}
@ -343,11 +604,11 @@ func TestRestrictedProfile(t *testing.T) {
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Name: "dbg", Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -357,38 +618,69 @@ func TestRestrictedProfile(t *testing.T) {
},
"debug by pod copy": {
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{Name: "dbg", Image: "dbgimage"},
},
},
},
containerName: "dbg",
target: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -408,7 +700,7 @@ func TestRestrictedProfile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -425,11 +717,11 @@ func TestRestrictedProfile(t *testing.T) {
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: pointer.Bool(true),
RunAsNonRoot: ptr.To(true),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
AllowPrivilegeEscalation: pointer.Bool(false),
AllowPrivilegeEscalation: ptr.To(false),
SeccompProfile: &corev1.SeccompProfile{Type: "RuntimeDefault"},
},
},
@ -441,7 +733,8 @@ func TestRestrictedProfile(t *testing.T) {
for name, test := range tests {
t.Run(name, func(t *testing.T) {
err := (&restrictedProfile{}).Apply(test.pod, test.containerName, test.target)
applier := &restrictedProfile{KeepFlags{InitContainers: true}}
err := applier.Apply(test.pod, test.containerName, test.target)
if (err != nil) != test.expectErr {
t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
}
@ -506,27 +799,58 @@ func TestNetAdminProfile(t *testing.T) {
{
name: "debug by pod copy",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{Name: "dbg", Image: "dbgimage"},
},
},
},
containerName: "dbg",
target: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
@ -548,7 +872,13 @@ func TestNetAdminProfile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{
Name: "dbg",
Image: "dbgimage",
@ -566,14 +896,20 @@ func TestNetAdminProfile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
@ -665,7 +1001,8 @@ func TestNetAdminProfile(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := (&netadminProfile{}).Apply(test.pod, test.containerName, test.target)
applier := &netadminProfile{KeepFlags{InitContainers: true}}
err := applier.Apply(test.pod, test.containerName, test.target)
if (err == nil) != (test.expectErr == nil) || (err != nil && test.expectErr != nil && err.Error() != test.expectErr.Error()) {
t.Fatalf("expect error: %v, got error: %v", test.expectErr, err)
}
@ -718,7 +1055,7 @@ func TestSysAdminProfile(t *testing.T) {
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Name: "dbg", Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
},
},
},
@ -728,37 +1065,68 @@ func TestSysAdminProfile(t *testing.T) {
{
name: "debug by pod copy",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{Name: "dbg", Image: "dbgimage"},
},
},
},
containerName: "dbg",
target: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
ObjectMeta: metav1.ObjectMeta{
Name: "podcopy",
Labels: map[string]string{
"app": "podcopy",
},
Annotations: map[string]string{
"test": "test",
},
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
expectPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{{Name: "init-container"}},
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
},
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -768,7 +1136,13 @@ func TestSysAdminProfile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
{
Name: "dbg",
Image: "dbgimage",
@ -786,7 +1160,13 @@ func TestSysAdminProfile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{Name: "app", Image: "appimage"},
{
Name: "app",
Image: "appimage",
LivenessProbe: &corev1.Probe{},
ReadinessProbe: &corev1.Probe{},
StartupProbe: &corev1.Probe{},
},
},
},
},
@ -799,14 +1179,14 @@ func TestSysAdminProfile(t *testing.T) {
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"SYS_PTRACE"},
},
},
},
},
ShareProcessNamespace: pointer.Bool(true),
ShareProcessNamespace: ptr.To(true),
},
},
},
@ -839,7 +1219,7 @@ func TestSysAdminProfile(t *testing.T) {
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
},
VolumeMounts: []corev1.VolumeMount{{Name: "host-root", MountPath: "/host"}},
},
@ -884,7 +1264,7 @@ func TestSysAdminProfile(t *testing.T) {
Name: "dbg",
Image: "dbgimage",
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Privileged: ptr.To(true),
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{"SYS_PTRACE"},
},
@ -899,7 +1279,8 @@ func TestSysAdminProfile(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := (&sysadminProfile{}).Apply(test.pod, test.containerName, test.target)
applier := &sysadminProfile{KeepFlags{InitContainers: true}}
err := applier.Apply(test.pod, test.containerName, test.target)
if (err == nil) != (test.expectErr == nil) || (err != nil && test.expectErr != nil && err.Error() != test.expectErr.Error()) {
t.Fatalf("expect error: %v, got error: %v", test.expectErr, err)
}

View File

@ -103,7 +103,10 @@ var (
kubectl delete pod foo --force
# Delete all pods
kubectl delete pods --all`))
kubectl delete pods --all
# Delete all pods only if the user confirms the deletion
kubectl delete pods --all --interactive`))
)
type DeleteOptions struct {
@ -521,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))
fmt.Fprintf(o.Out, i18n.T("You are about to delete the following %d resource(s):\n"), len(infos)) //nolint:errcheck
for _, info := range infos {
groupKind := info.Mapping.GroupVersionKind
kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
@ -529,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)
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name) //nolint:errcheck
}
fmt.Fprintf(o.Out, i18n.T("Do you want to continue?")+" (y/n): ")
fmt.Fprint(o.Out, i18n.T("Do you want to continue?")+" (y/N): ") //nolint:errcheck
var input string
_, err := fmt.Fscan(o.In, &input)
_, err := fmt.Fscanln(o.In, &input)
if err != nil {
return false
}

View File

@ -36,7 +36,7 @@ import (
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
func fakecmd() *cobra.Command {
@ -60,8 +60,8 @@ func TestDeleteFlagValidation(t *testing.T) {
}{
{
flags: DeleteFlags{
Raw: pointer.String("test"),
Interactive: pointer.Bool(true),
Raw: ptr.To("test"),
Interactive: ptr.To(true),
},
expectedErr: "--interactive can not be used with --raw",
},
@ -306,7 +306,7 @@ func TestDeleteObject(t *testing.T) {
func TestPreviewResultEqualToResult(t *testing.T) {
deleteFlags := NewDeleteCommandFlags("")
deleteFlags.Interactive = pointer.Bool(true)
deleteFlags.Interactive = ptr.To(true)
tf := cmdtesting.NewTestFactory().WithNamespace("test")
defer tf.Cleanup()
@ -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" {

View File

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

View File

@ -161,7 +161,7 @@ func NewCmdDiff(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Co
// command it means changes were found.
// Thus, it should return status code greater than 1.
cmd.SetFlagErrorFunc(func(command *cobra.Command, err error) error {
cmdutil.CheckDiffErr(cmdutil.UsageErrorf(cmd, err.Error()))
cmdutil.CheckDiffErr(cmdutil.UsageErrorf(cmd, "%s", err.Error()))
return nil
})

View File

@ -20,7 +20,6 @@ import (
"bytes"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"testing"
@ -65,6 +64,7 @@ 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)
@ -130,7 +130,7 @@ func TestDiffVersion(t *testing.T) {
if err != nil {
t.Fatal(err)
}
fcontent, err := os.ReadFile(path.Join(diff.Dir.Name, obj.Name()))
fcontent, err := os.ReadFile(filepath.Join(diff.Dir.Name, obj.Name()))
if err != nil {
t.Fatal(err)
}
@ -201,7 +201,7 @@ func TestDiffer(t *testing.T) {
if err != nil {
t.Fatal(err)
}
fcontent, err := os.ReadFile(path.Join(diff.From.Dir.Name, obj.Name()))
fcontent, err := os.ReadFile(filepath.Join(diff.From.Dir.Name, obj.Name()))
if err != nil {
t.Fatal(err)
}
@ -210,7 +210,7 @@ func TestDiffer(t *testing.T) {
t.Fatalf("File has %q, expected %q", string(fcontent), econtent)
}
fcontent, err = os.ReadFile(path.Join(diff.To.Dir.Name, obj.Name()))
fcontent, err = os.ReadFile(filepath.Join(diff.To.Dir.Name, obj.Name()))
if err != nil {
t.Fatal(err)
}
@ -286,12 +286,12 @@ metadata:
t.Fatal(err)
}
actualFromContent, _ := os.ReadFile(path.Join(diff.From.Dir.Name, obj.Name()))
actualFromContent, _ := os.ReadFile(filepath.Join(diff.From.Dir.Name, obj.Name()))
if string(actualFromContent) != tc.expectedFromContent {
t.Fatalf("File has %q, expected %q", string(actualFromContent), tc.expectedFromContent)
}
actualToContent, _ := os.ReadFile(path.Join(diff.To.Dir.Name, obj.Name()))
actualToContent, _ := os.ReadFile(filepath.Join(diff.To.Dir.Name, obj.Name()))
if string(actualToContent) != tc.expectedToContent {
t.Fatalf("File has %q, expected %q", string(actualToContent), tc.expectedToContent)
}

View File

@ -224,8 +224,6 @@ func NewCmdDrain(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra
}
cmd.Flags().BoolVar(&o.drainer.Force, "force", o.drainer.Force, "Continue even if there are pods that do not declare a controller.")
cmd.Flags().BoolVar(&o.drainer.IgnoreAllDaemonSets, "ignore-daemonsets", o.drainer.IgnoreAllDaemonSets, "Ignore DaemonSet-managed pods.")
cmd.Flags().BoolVar(&o.drainer.DeleteEmptyDirData, "delete-local-data", o.drainer.DeleteEmptyDirData, "Continue even if there are pods using emptyDir (local data that will be deleted when the node is drained).")
cmd.Flags().MarkDeprecated("delete-local-data", "This option is deprecated and will be deleted. Use --delete-emptydir-data.")
cmd.Flags().BoolVar(&o.drainer.DeleteEmptyDirData, "delete-emptydir-data", o.drainer.DeleteEmptyDirData, "Continue even if there are pods using emptyDir (local data that will be deleted when the node is drained).")
cmd.Flags().IntVar(&o.drainer.GracePeriodSeconds, "grace-period", o.drainer.GracePeriodSeconds, "Period of time in seconds given to each pod to terminate gracefully. If negative, the default value specified in the pod will be used.")
cmd.Flags().DurationVar(&o.drainer.Timeout, "timeout", o.drainer.Timeout, "The length of time to wait before giving up, zero means infinite")
@ -245,7 +243,7 @@ func (o *DrainCmdOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
var err error
if len(args) == 0 && !cmd.Flags().Changed("selector") {
return cmdutil.UsageErrorf(cmd, fmt.Sprintf("USAGE: %s [flags]", cmd.Use))
return cmdutil.UsageErrorf(cmd, "USAGE: %s [flags]", cmd.Use)
}
if len(args) > 0 && len(o.drainer.Selector) > 0 {
return cmdutil.UsageErrorf(cmd, "error: cannot specify both a node name and a --selector option")
@ -328,7 +326,7 @@ func (o *DrainCmdOptions) RunDrain() error {
return err
}
drainedNodes := sets.NewString()
drainedNodes := sets.New[string]()
var fatal []error
remainingNodes := []string{}
@ -343,7 +341,7 @@ func (o *DrainCmdOptions) RunDrain() error {
printObj(info.Object, o.Out)
} else {
fmt.Fprintf(o.ErrOut, "error: unable to drain node %q due to error:%s, continuing command...\n", info.Name, err)
fmt.Fprintf(o.ErrOut, "error: unable to drain node %q due to error: %s, continuing command...\n", info.Name, err)
if !drainedNodes.Has(info.Name) {
fatal = append(fatal, err)

View File

@ -42,7 +42,7 @@ import (
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/drain"
"k8s.io/kubectl/pkg/scheme"
utilpointer "k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
const (
@ -277,8 +277,8 @@ func TestDrain(t *testing.T) {
Kind: "ReplicationController",
Name: "rc",
UID: "123",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -309,8 +309,8 @@ func TestDrain(t *testing.T) {
APIVersion: "apps/v1",
Kind: "DaemonSet",
Name: "ds",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -330,8 +330,8 @@ func TestDrain(t *testing.T) {
APIVersion: "apps/v1",
Kind: "DaemonSet",
Name: "ds",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -354,8 +354,8 @@ func TestDrain(t *testing.T) {
APIVersion: "apps/v1",
Kind: "DaemonSet",
Name: "ds",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -404,8 +404,8 @@ func TestDrain(t *testing.T) {
APIVersion: "v1",
Kind: "Job",
Name: "job",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -431,8 +431,8 @@ func TestDrain(t *testing.T) {
APIVersion: "v1",
Kind: "Job",
Name: "job",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -473,8 +473,8 @@ func TestDrain(t *testing.T) {
APIVersion: "v1",
Kind: "ReplicaSet",
Name: "rs",
BlockOwnerDeletion: utilpointer.BoolPtr(true),
Controller: utilpointer.BoolPtr(true),
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
},
},
},
@ -635,17 +635,6 @@ func TestDrain(t *testing.T) {
expectDelete: true,
expectOutputToContain: "node/node drained",
},
{
description: "Ensure compatibility for --delete-local-data until fully deprecated",
node: node,
expected: cordonedNode,
pods: []corev1.Pod{jobPod},
rcs: []corev1.ReplicationController{rc},
args: []string{"node", "--force", "--delete-local-data=true"},
expectFatal: false,
expectDelete: true,
expectOutputToContain: "node/node drained",
},
{
description: "Job-managed terminated pod",
node: node,

View File

@ -103,6 +103,6 @@ func NewCmdEdit(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.
"Defaults to the line ending native to your platform.")
cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-edit")
cmdutil.AddApplyAnnotationVarFlags(cmd, &o.ApplyAnnotation)
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, edit will operate on the subresource of the requested object.", editor.SupportedSubresources...)
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, edit will operate on the subresource of the requested object.")
return cmd
}

View File

@ -30,8 +30,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/spf13/cobra"
yaml "gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericiooptions"
@ -41,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 {
@ -173,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.NewString()
testcases := sets.New[string]()
filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
@ -195,7 +194,7 @@ func TestEdit(t *testing.T) {
t.Fatalf("Error locating edit testcases")
}
for _, testcaseName := range testcases.List() {
for _, testcaseName := range testcases.UnsortedList() {
t.Run(testcaseName, func(t *testing.T) {
i = 0
name = testcaseName

View File

@ -25,7 +25,7 @@ import (
"os"
"strings"
yaml "gopkg.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\",\"creationTimestamp\":null,\"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\",\"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","creationTimestamp":null,"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","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","creationTimestamp":null,"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","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,7 +33,6 @@
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app": "nginx"
}

View File

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

View File

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

View File

@ -33,7 +33,6 @@
},
"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\",\"creationTimestamp\":null,\"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\",\"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","creationTimestamp":null,"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","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","creationTimestamp":null,"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","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\",\"creationTimestamp\":null,\"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\",\"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","creationTimestamp":null,"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","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","creationTimestamp":null,"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","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

@ -18,11 +18,12 @@ package events
import (
"bytes"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"testing"
"time"
)
func TestPrintObj(t *testing.T) {
@ -50,7 +51,7 @@ func TestPrintObj(t *testing.T) {
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-20 * time.Minute)),
Series: &corev1.EventSeries{
@ -59,7 +60,7 @@ func TestPrintObj(t *testing.T) {
},
},
expected: `LAST SEEN TYPE REASON OBJECT MESSAGE
12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
`,
},
{
@ -83,7 +84,7 @@ func TestPrintObj(t *testing.T) {
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-20 * time.Minute)),
Series: &corev1.EventSeries{
@ -105,7 +106,7 @@ func TestPrintObj(t *testing.T) {
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-15 * time.Minute)),
Series: &corev1.EventSeries{
@ -116,8 +117,8 @@ func TestPrintObj(t *testing.T) {
},
},
expected: `NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE
foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
bar 11m (x3 over 15m) Normal ScalingReplicaSet Deployment/bar2 Scaled up replica set bar-002 to 1
foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
bar 11m (x3 over 15m) Normal ScalingReplicaSet Deployment/bar2 Scaled up replica set bar-002 from 0 to 1
`,
},
{
@ -139,7 +140,7 @@ bar 11m (x3 over 15m) Normal ScalingReplicaSet Deployment/bar2 Scaled up replica
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-20 * time.Minute)),
Series: &corev1.EventSeries{
@ -147,7 +148,7 @@ bar 11m (x3 over 15m) Normal ScalingReplicaSet Deployment/bar2 Scaled up replica
LastObservedTime: metav1.NewMicroTime(time.Now().Add(-12 * time.Minute)),
},
},
expected: "12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1\n",
expected: "12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1\n",
},
{
printer: EventPrinter{
@ -168,7 +169,7 @@ bar 11m (x3 over 15m) Normal ScalingReplicaSet Deployment/bar2 Scaled up replica
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-20 * time.Minute)),
Series: &corev1.EventSeries{
@ -177,7 +178,7 @@ bar 11m (x3 over 15m) Normal ScalingReplicaSet Deployment/bar2 Scaled up replica
},
},
expected: `NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE
foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
`,
},
{
@ -199,7 +200,7 @@ foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-20 * time.Minute)),
Series: &corev1.EventSeries{
@ -207,7 +208,7 @@ foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica
LastObservedTime: metav1.NewMicroTime(time.Now().Add(-12 * time.Minute)),
},
},
expected: `foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
expected: `foo 12m (x3 over 20m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
`,
},
{

View File

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

View File

@ -50,7 +50,7 @@ func getFakeEvents() *corev1.EventList {
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-30 * time.Minute)),
Series: &corev1.EventSeries{
@ -72,7 +72,7 @@ func getFakeEvents() *corev1.EventList {
},
Type: corev1.EventTypeWarning,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-28 * time.Minute)),
Series: &corev1.EventSeries{
@ -94,7 +94,7 @@ func getFakeEvents() *corev1.EventList {
},
Type: corev1.EventTypeNormal,
Reason: "ScalingReplicaSet",
Message: "Scaled up replica set bar-002 to 1",
Message: "Scaled up replica set bar-002 from 0 to 1",
ReportingController: "deployment-controller",
EventTime: metav1.NewMicroTime(time.Now().Add(-25 * time.Minute)),
Series: &corev1.EventSeries{
@ -135,9 +135,9 @@ func TestEventIsSorted(t *testing.T) {
}
expected := `NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE
foo 20m (x3 over 30m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
foo 18m (x3 over 28m) Warning ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
otherfoo 15m (x3 over 25m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
foo 20m (x3 over 30m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
foo 18m (x3 over 28m) Warning ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
otherfoo 15m (x3 over 25m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
`
if e, a := expected, buf.String(); e != a {
t.Errorf("expected\n%v\ngot\n%v", e, a)
@ -172,9 +172,9 @@ func TestEventNoHeaders(t *testing.T) {
t.Fatal(err)
}
expected := `foo 20m (x3 over 30m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
foo 18m (x3 over 28m) Warning ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
otherfoo 15m (x3 over 25m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
expected := `foo 20m (x3 over 30m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
foo 18m (x3 over 28m) Warning ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
otherfoo 15m (x3 over 25m) Normal ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
`
if e, a := expected, buf.String(); e != a {
t.Errorf("expected\n%v\ngot\n%v", e, a)
@ -211,7 +211,7 @@ func TestEventFiltered(t *testing.T) {
}
expected := `NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE
foo 18m (x3 over 28m) Warning ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 to 1
foo 18m (x3 over 28m) Warning ScalingReplicaSet Deployment/bar Scaled up replica set bar-002 from 0 to 1
`
if e, a := expected, buf.String(); e != a {
t.Errorf("expected\n%v\ngot\n%v", e, a)

View File

@ -114,18 +114,26 @@ 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 (*DefaultRemoteExecutor) Execute(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
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 {
exec, err := createExecutor(url, config)
if err != nil {
return err
}
return exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{
return exec.StreamWithContext(ctx, remotecommand.StreamOptions{
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
@ -147,7 +155,9 @@ func createExecutor(url *url.URL, config *restclient.Config) (remotecommand.Exec
if err != nil {
return nil, err
}
exec, err = remotecommand.NewFallbackExecutor(websocketExec, exec, httpstream.IsUpgradeFailure)
exec, err = remotecommand.NewFallbackExecutor(websocketExec, exec, func(err error) bool {
return httpstream.IsUpgradeFailure(err) || httpstream.IsHTTPSProxyError(err)
})
if err != nil {
return nil, err
}
@ -200,17 +210,8 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
}
if argsLenAtDash > -1 {
p.Command = argsIn[argsLenAtDash:]
} else if len(argsIn) > 1 {
if !p.Quiet {
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.\n")
}
p.Command = argsIn[1:]
} else if len(argsIn) > 0 && len(p.FilenameOptions.Filenames) != 0 {
if !p.Quiet {
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.\n")
}
p.Command = argsIn[0:]
p.ResourceName = ""
} else if len(argsIn) > 1 || (len(argsIn) > 0 && len(p.FilenameOptions.Filenames) != 0) {
return cmdutil.UsageErrorf(cmd, "exec [POD] [COMMAND] is not supported anymore. Use exec [POD] -- [COMMAND] instead")
}
var err error
@ -223,7 +224,7 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
p.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return cmdutil.UsageErrorf(cmd, err.Error())
return cmdutil.UsageErrorf(cmd, "%s", err.Error())
}
p.Builder = f.NewBuilder

View File

@ -18,6 +18,7 @@ package exec
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
@ -45,6 +46,10 @@ 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
}
@ -110,20 +115,17 @@ func TestPodAndContainer(t *testing.T) {
p: &ExecOptions{},
args: []string{"foo", "cmd"},
argsLenAtDash: -1,
expectedPod: "foo",
expectedArgs: []string{"cmd"},
expectError: true,
name: "cmd, cmd is behind dash",
obj: execPod(),
},
{
p: &ExecOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
args: []string{"foo", "cmd"},
argsLenAtDash: -1,
expectedPod: "foo",
expectedContainer: "bar",
expectedArgs: []string{"cmd"},
name: "cmd, container in flag",
obj: execPod(),
p: &ExecOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
args: []string{"foo", "cmd"},
argsLenAtDash: -1,
expectError: true,
name: "cmd, container in flag",
obj: execPod(),
},
}
for _, test := range tests {
@ -238,8 +240,8 @@ func TestExec(t *testing.T) {
Executor: ex,
}
cmd := NewCmdExec(tf, genericiooptions.NewTestIOStreamsDiscard())
args := []string{"pod/foo", "command"}
if err := params.Complete(tf, cmd, args, -1); err != nil {
args := []string{"pod/foo", "--", "command"}
if err := params.Complete(tf, cmd, args, 1); err != nil {
t.Fatal(err)
}
err := params.Run()

View File

@ -56,83 +56,113 @@ 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"
)
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.
// 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
// Client capable of fetching openapi documents from the user's cluster
OpenAPIV3Client openapiclient.Client
genericiooptions.IOStreams
}
func NewExplainOptions(parent string, streams genericiooptions.IOStreams) *ExplainOptions {
return &ExplainOptions{
IOStreams: streams,
CmdParent: parent,
// NewExplainFlags returns a default ExplainFlags
func NewExplainFlags(streams genericiooptions.IOStreams) *ExplainFlags {
return &ExplainFlags{
OutputFormat: plaintextTemplateName,
IOStreams: streams,
}
}
// 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 {
o := NewExplainOptions(parent, streams)
flags := NewExplainFlags(streams)
cmd := &cobra.Command{
Use: "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [--output=plaintext|plaintext-openapiv2]",
Use: "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [-o|--output=plaintext|plaintext-openapiv2]",
DisableFlagsInUseLine: true,
Short: i18n.T("Get documentation for a resource"),
Long: explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: explainExamples,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
o, err := flags.ToOptions(f, parent, args)
cmdutil.CheckErr(err)
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.")
// Only enable --output as a valid flag if the feature is enabled
cmd.Flags().StringVar(&o.OutputFormat, "output", plaintextTemplateName, "Format in which to render the schema. Valid values are: (plaintext, plaintext-openapiv2).")
flags.AddFlags(cmd)
return cmd
}
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
}
type ExplainOptions struct {
genericiooptions.IOStreams
// Only openapi v3 needs the discovery client.
o.OpenAPIV3Client, err = f.OpenAPIV3Client()
if err != nil {
return err
}
Recursive bool
APIVersion string
// Name of the template to use with the openapiv3 template renderer.
OutputFormat string
// Lazy-load the OpenAPI V2 Resources, so they're not loaded when using OpenAPI V3.
o.openAPIGetter = f
o.args = args
return nil
CmdParent string
args []string
Mapper meta.RESTMapper
openAPIGetter openapi.OpenAPIResourcesGetter
// Client capable of fetching openapi documents from the user's cluster
OpenAPIV3Client openapiclient.Client
}
func (o *ExplainOptions) Validate() error {

View File

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

View File

@ -225,12 +225,12 @@ func (flags *ExposeServiceFlags) AddFlags(cmd *cobra.Command) {
}
func (flags *ExposeServiceFlags) ToOptions(cmd *cobra.Command, args []string) (*ExposeServiceOptions, error) {
dryRunStratergy, err := cmdutil.GetDryRunStrategy(cmd)
dryRunStrategy, err := cmdutil.GetDryRunStrategy(cmd)
if err != nil {
return nil, err
}
cmdutil.PrintFlagsWithDryRunStrategy(flags.PrintFlags, dryRunStratergy)
cmdutil.PrintFlagsWithDryRunStrategy(flags.PrintFlags, dryRunStrategy)
printer, err := flags.PrintFlags.ToPrinter()
if err != nil {
return nil, err
@ -243,7 +243,7 @@ func (flags *ExposeServiceFlags) ToOptions(cmd *cobra.Command, args []string) (*
}
e := &ExposeServiceOptions{
DryRunStrategy: dryRunStratergy,
DryRunStrategy: dryRunStrategy,
PrintObj: printer.PrintObj,
Recorder: recorder,
IOStreams: flags.IOStreams,

View File

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

View File

@ -19,6 +19,7 @@ package get
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"reflect"
@ -161,7 +162,7 @@ func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error
// we need an actual value in order to retrieve the package path for an object.
// using reflect.Indirect indiscriminately is valid here, as all runtime.Objects are supposed to be pointers.
if printers.InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj)).Type().PkgPath()) {
return fmt.Errorf(printers.InternalObjectPrinterErr)
return errors.New(printers.InternalObjectPrinterErr)
}
if _, found := out.(*tabwriter.Writer); !found {
@ -210,7 +211,7 @@ func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jso
switch u := obj.(type) {
case *metav1.WatchEvent:
if printers.InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(u.Object.Object)).Type().PkgPath()) {
return fmt.Errorf(printers.InternalObjectPrinterErr)
return errors.New(printers.InternalObjectPrinterErr)
}
unstructuredObject, err := runtime.DefaultUnstructuredConverter.ToUnstructured(u.Object.Object)
if err != nil {

View File

@ -47,9 +47,8 @@ import (
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/interrupt"
"k8s.io/kubectl/pkg/util/slice"
"k8s.io/kubectl/pkg/util/templates"
utilpointer "k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)
// GetOptions contains the input to the get command.
@ -91,8 +90,8 @@ var (
Prints a table of the most important information about the specified resources.
You can filter the list using a label selector and the --selector flag. If the
desired resource type is namespaced you will only see results in your current
namespace unless you pass --all-namespaces.
desired resource type is namespaced you will only see results in the current
namespace if you don't specify any namespace.
By specifying the output as 'template' and providing a Go template as the value
of the --template flag, you can filter the attributes of the fetched resources.`))
@ -132,15 +131,19 @@ var (
kubectl get rc/web service/frontend pods/web-pod-13je7
# List the 'status' subresource for a single pod
kubectl get pod web-pod-13je7 --subresource status`))
kubectl get pod web-pod-13je7 --subresource status
# List all deployments in namespace 'backend'
kubectl get deployments.apps --namespace backend
# List all pods existing in all namespaces
kubectl get pods --all-namespaces`))
)
const (
useServerPrintColumns = "server-print"
)
var supportedSubresources = []string{"status", "scale"}
// NewGetOptions returns a GetOptions with default chunk size 500.
func NewGetOptions(parent string, streams genericiooptions.IOStreams) *GetOptions {
return &GetOptions{
@ -186,7 +189,7 @@ func NewCmdGet(parent string, f cmdutil.Factory, streams genericiooptions.IOStre
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to get from a server.")
cmdutil.AddChunkSizeFlag(cmd, &o.ChunkSize)
cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, gets the subresource of the requested object.", supportedSubresources...)
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, gets the subresource of the requested object.")
return cmd
}
@ -267,9 +270,13 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
}
switch {
case o.Watch || o.WatchOnly:
case o.Watch:
if len(o.SortBy) > 0 {
fmt.Fprintf(o.IOStreams.ErrOut, "warning: --watch or --watch-only requested, --sort-by will be ignored\n")
fmt.Fprintf(o.IOStreams.ErrOut, "warning: --watch requested, --sort-by will be ignored for watch events received\n")
}
case o.WatchOnly:
if len(o.SortBy) > 0 {
fmt.Fprintf(o.IOStreams.ErrOut, "warning: --watch-only requested, --sort-by will be ignored\n")
}
default:
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
@ -280,7 +287,7 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
usageString = fmt.Sprintf("%s\nUse \"%s explain <resource>\" for a detailed description of that resource (e.g. %[2]s explain pods).", usageString, fullCmdName)
}
return cmdutil.UsageErrorf(cmd, usageString)
return cmdutil.UsageErrorf(cmd, "%s", usageString)
}
}
@ -309,9 +316,6 @@ func (o *GetOptions) Validate() error {
if o.OutputWatchEvents && !(o.Watch || o.WatchOnly) {
return fmt.Errorf("--output-watch-events option can only be used with --watch or --watch-only")
}
if len(o.Subresource) > 0 && !slice.ContainsString(supportedSubresources, o.Subresource, nil) {
return fmt.Errorf("invalid subresource value: %q. Must be one of %v", o.Subresource, supportedSubresources)
}
return nil
}
@ -482,7 +486,7 @@ func (o *GetOptions) Run(f cmdutil.Factory, args []string) error {
}
allErrs := []error{}
errs := sets.NewString()
errs := sets.New[string]()
infos, err := r.Infos()
if err != nil {
allErrs = append(allErrs, err)
@ -627,7 +631,7 @@ func (o *GetOptions) watch(f cmdutil.Factory, args []string) error {
info := infos[0]
mapping := info.ResourceMapping()
outputObjects := utilpointer.BoolPtr(!o.WatchOnly)
outputObjects := ptr.To(!o.WatchOnly)
printer, err := o.ToPrinter(mapping, outputObjects, o.AllNamespaces, false)
if err != nil {
return err

View File

@ -1438,7 +1438,6 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"creationTimestamp": null,
"name": "foo",
"namespace": "test",
"resourceVersion": "10"
@ -1457,7 +1456,6 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"creationTimestamp": null,
"name": "bar",
"namespace": "test",
"resourceVersion": "11"
@ -1476,7 +1474,6 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"creationTimestamp": null,
"name": "baz",
"namespace": "test",
"resourceVersion": "12"
@ -2367,10 +2364,10 @@ DELETED test pod/foo 0/0 0 <unknown> <none>
},
{
format: "json",
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":{}}}
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":{}}}
`,
},
{
@ -2379,7 +2376,6 @@ DELETED test pod/foo 0/0 0 <unknown> <none>
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: bar
namespace: test
resourceVersion: "9"
@ -2397,7 +2393,6 @@ object:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: foo
namespace: test
resourceVersion: "10"
@ -2415,7 +2410,6 @@ object:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: foo
namespace: test
resourceVersion: "11"
@ -2433,7 +2427,6 @@ object:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: foo
namespace: test
resourceVersion: "12"

View File

@ -32,8 +32,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/client-go/util/jsonpath"
"github.com/fvbommel/sortorder"
)
// SortingPrinter sorts list types before delegating to another printer.
@ -180,7 +178,7 @@ func isLess(i, j reflect.Value) (bool, error) {
case reflect.Float32, reflect.Float64:
return i.Float() < j.Float(), nil
case reflect.String:
return sortorder.NaturalLess(i.String(), j.String()), nil
return i.String() < j.String(), nil
case reflect.Pointer:
return isLess(i.Elem(), j.Elem())
case reflect.Struct:
@ -274,11 +272,11 @@ func isLess(i, j reflect.Value) (bool, error) {
// check if it's a Quantity
itypeQuantity, err := resource.ParseQuantity(itype)
if err != nil {
return sortorder.NaturalLess(itype, jtype), nil
return itype < jtype, nil
}
jtypeQuantity, err := resource.ParseQuantity(jtype)
if err != nil {
return sortorder.NaturalLess(itype, jtype), nil
return itype < jtype, nil
}
// Both strings are quantity
return itypeQuantity.Cmp(jtypeQuantity) < 0, nil

View File

@ -31,6 +31,7 @@ import (
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/utils/ptr"
)
func toUnstructuredOrDie(data []byte) *unstructured.Unstructured {
@ -103,8 +104,6 @@ func createUnstructuredPodResource(t *testing.T, memReq, memLimit, cpuReq, cpuLi
}
func TestSortingPrinter(t *testing.T) {
intPtr := func(val int32) *int32 { return &val }
a := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "a",
@ -272,17 +271,17 @@ func TestSortingPrinter(t *testing.T) {
Items: []corev1.ReplicationController{
{
Spec: corev1.ReplicationControllerSpec{
Replicas: intPtr(5),
Replicas: ptr.To[int32](5),
},
},
{
Spec: corev1.ReplicationControllerSpec{
Replicas: intPtr(1),
Replicas: ptr.To[int32](1),
},
},
{
Spec: corev1.ReplicationControllerSpec{
Replicas: intPtr(9),
Replicas: ptr.To[int32](9),
},
},
},
@ -291,17 +290,17 @@ func TestSortingPrinter(t *testing.T) {
Items: []corev1.ReplicationController{
{
Spec: corev1.ReplicationControllerSpec{
Replicas: intPtr(1),
Replicas: ptr.To[int32](1),
},
},
{
Spec: corev1.ReplicationControllerSpec{
Replicas: intPtr(5),
Replicas: ptr.To[int32](5),
},
},
{
Spec: corev1.ReplicationControllerSpec{
Replicas: intPtr(9),
Replicas: ptr.To[int32](9),
},
},
},

View File

@ -21,8 +21,8 @@ import (
"reflect"
"strings"
jsonpatch "github.com/evanphx/json-patch"
"github.com/spf13/cobra"
jsonpatch "gopkg.in/evanphx/json-patch.v4"
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/api/meta"

View File

@ -41,6 +41,7 @@ import (
"k8s.io/kubectl/pkg/util"
"k8s.io/kubectl/pkg/util/completion"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/interrupt"
"k8s.io/kubectl/pkg/util/templates"
)
@ -57,15 +58,33 @@ var (
# Return snapshot logs from pod nginx with only one container
kubectl logs nginx
# Return snapshot logs from pod nginx, prefixing each line with the source pod and container name
kubectl logs nginx --prefix
# Return snapshot logs from pod nginx, limiting output to 500 bytes
kubectl logs nginx --limit-bytes=500
# Return snapshot logs from pod nginx, waiting up to 20 seconds for it to start running.
kubectl logs nginx --pod-running-timeout=20s
# Return snapshot logs from pod nginx with multi containers
kubectl logs nginx --all-containers=true
# Return snapshot logs from all pods in the deployment nginx
kubectl logs deployment/nginx --all-pods=true
# Return snapshot logs from all containers in pods defined by label app=nginx
kubectl logs -l app=nginx --all-containers=true
# Return snapshot logs from all pods defined by label app=nginx, limiting concurrent log requests to 10 pods
kubectl logs -l app=nginx --max-log-requests=10
# Return snapshot of previous terminated ruby container logs from pod web-1
kubectl logs -p -c ruby web-1
# Begin streaming the logs from pod nginx, continuing even if errors occur
kubectl logs nginx -f --ignore-errors=true
# Begin streaming the logs of the ruby container in pod web-1
kubectl logs -f -c ruby web-1
@ -77,6 +96,9 @@ var (
# Show all logs from pod nginx written in the last hour
kubectl logs --since=1h nginx
# Show all logs with timestamps from pod nginx starting from August 30, 2024, at 06:00:00 UTC
kubectl logs nginx --since-time=2024-08-30T06:00:00Z --timestamps=true
# Show logs from a kubelet with an expired serving certificate
kubectl logs --insecure-skip-tls-verify-backend nginx
@ -99,10 +121,11 @@ type LogsOptions struct {
Namespace string
ResourceArg string
AllContainers bool
AllPods bool
Options runtime.Object
Resources []string
ConsumeRequestFn func(rest.ResponseWrapper, io.Writer) error
ConsumeRequestFn func(context.Context, rest.ResponseWrapper, io.Writer) error
// PodLogOptions
SinceTime string
@ -122,10 +145,11 @@ type LogsOptions struct {
MaxFollowConcurrency int
Prefix bool
Object runtime.Object
GetPodTimeout time.Duration
RESTClientGetter genericclioptions.RESTClientGetter
LogsForObject polymorphichelpers.LogsForObjectFunc
Object runtime.Object
GetPodTimeout time.Duration
RESTClientGetter genericclioptions.RESTClientGetter
LogsForObject polymorphichelpers.LogsForObjectFunc
AllPodLogsForObject polymorphichelpers.AllPodLogsForObjectFunc
genericiooptions.IOStreams
@ -134,10 +158,9 @@ type LogsOptions struct {
containerNameFromRefSpecRegexp *regexp.Regexp
}
func NewLogsOptions(streams genericiooptions.IOStreams, allContainers bool) *LogsOptions {
func NewLogsOptions(streams genericiooptions.IOStreams) *LogsOptions {
return &LogsOptions{
IOStreams: streams,
AllContainers: allContainers,
Tail: -1,
MaxFollowConcurrency: 5,
@ -147,7 +170,7 @@ func NewLogsOptions(streams genericiooptions.IOStreams, allContainers bool) *Log
// NewCmdLogs creates a new pod logs command
func NewCmdLogs(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
cmd := &cobra.Command{
Use: logsUsageStr,
@ -167,6 +190,7 @@ func NewCmdLogs(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Co
}
func (o *LogsOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&o.AllPods, "all-pods", o.AllPods, "Get logs from all pod(s). Sets prefix to true.")
cmd.Flags().BoolVar(&o.AllContainers, "all-containers", o.AllContainers, "Get all containers' logs in the pod(s).")
cmd.Flags().BoolVarP(&o.Follow, "follow", "f", o.Follow, "Specify if the logs should be streamed.")
cmd.Flags().BoolVar(&o.Timestamps, "timestamps", o.Timestamps, "Include timestamps on each line in the log output")
@ -243,6 +267,11 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str
default:
return cmdutil.UsageErrorf(cmd, "%s", logsUsageErrStr)
}
if o.AllPods {
o.Prefix = true
}
var err error
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
@ -263,6 +292,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str
o.RESTClientGetter = f
o.LogsForObject = polymorphichelpers.LogsForObjectFn
o.AllPodLogsForObject = polymorphichelpers.AllPodLogsForObjectFn
if o.Object == nil {
builder := f.NewBuilder().
@ -328,7 +358,13 @@ func (o LogsOptions) Validate() error {
// RunLogs retrieves a pod log
func (o LogsOptions) RunLogs() error {
requests, err := o.LogsForObject(o.RESTClientGetter, o.Object, o.Options, o.GetPodTimeout, o.AllContainers)
var requests map[corev1.ObjectReference]rest.ResponseWrapper
var err error
if o.AllPods {
requests, err = o.AllPodLogsForObject(o.RESTClientGetter, o.Object, o.Options, o.GetPodTimeout, o.AllContainers)
} else {
requests, err = o.LogsForObject(o.RESTClientGetter, o.Object, o.Options, o.GetPodTimeout, o.AllContainers)
}
if err != nil {
return err
}
@ -340,14 +376,21 @@ func (o LogsOptions) RunLogs() error {
len(requests), o.MaxFollowConcurrency,
)
}
return o.parallelConsumeRequest(requests)
}
return o.sequentialConsumeRequest(requests)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
intr := interrupt.New(nil, cancel)
return intr.Run(func() error {
if o.Follow && len(requests) > 1 {
return o.parallelConsumeRequest(ctx, requests)
}
return o.sequentialConsumeRequest(ctx, requests)
})
}
func (o LogsOptions) parallelConsumeRequest(requests map[corev1.ObjectReference]rest.ResponseWrapper) error {
func (o LogsOptions) parallelConsumeRequest(ctx context.Context, requests map[corev1.ObjectReference]rest.ResponseWrapper) error {
reader, writer := io.Pipe()
wg := &sync.WaitGroup{}
wg.Add(len(requests))
@ -355,7 +398,7 @@ func (o LogsOptions) parallelConsumeRequest(requests map[corev1.ObjectReference]
go func(objRef corev1.ObjectReference, request rest.ResponseWrapper) {
defer wg.Done()
out := o.addPrefixIfNeeded(objRef, writer)
if err := o.ConsumeRequestFn(request, out); err != nil {
if err := o.ConsumeRequestFn(ctx, request, out); err != nil {
if !o.IgnoreLogErrors {
writer.CloseWithError(err)
@ -378,10 +421,10 @@ func (o LogsOptions) parallelConsumeRequest(requests map[corev1.ObjectReference]
return err
}
func (o LogsOptions) sequentialConsumeRequest(requests map[corev1.ObjectReference]rest.ResponseWrapper) error {
func (o LogsOptions) sequentialConsumeRequest(ctx context.Context, requests map[corev1.ObjectReference]rest.ResponseWrapper) error {
for objRef, request := range requests {
out := o.addPrefixIfNeeded(objRef, o.Out)
if err := o.ConsumeRequestFn(request, out); err != nil {
if err := o.ConsumeRequestFn(ctx, request, out); err != nil {
if !o.IgnoreLogErrors {
return err
}
@ -422,8 +465,8 @@ func (o LogsOptions) addPrefixIfNeeded(ref corev1.ObjectReference, writer io.Wri
// A successful read returns err == nil, not err == io.EOF.
// Because the function is defined to read from request until io.EOF, it does
// not treat an io.EOF as an error to be reported.
func DefaultConsumeRequest(request rest.ResponseWrapper, out io.Writer) error {
readCloser, err := request.Stream(context.TODO())
func DefaultConsumeRequest(ctx context.Context, request rest.ResponseWrapper, out io.Writer) error {
readCloser, err := request.Stream(ctx)
if err != nil {
return err
}

View File

@ -29,6 +29,7 @@ import (
"testing/iotest"
"time"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -62,7 +63,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
@ -83,7 +84,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Prefix = true
@ -92,6 +93,35 @@ func TestLog(t *testing.T) {
},
expectedOutSubstrings: []string{"[pod/test-pod/test-container] test log content\n"},
},
{
name: "stateful set logs with all pods",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
mock := &logTestMock{
logsForObjectRequests: map[corev1.ObjectReference]restclient.ResponseWrapper{
{
Kind: "Pod",
Name: "test-sts-0",
FieldPath: "spec.containers{test-container}",
}: &responseWrapperMock{data: strings.NewReader("test log content for pod test-sts-0\n")},
{
Kind: "Pod",
Name: "test-sts-1",
FieldPath: "spec.containers{test-container}",
}: &responseWrapperMock{data: strings.NewReader("test log content for pod test-sts-1\n")},
},
}
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Prefix = true
return o
},
expectedOutSubstrings: []string{
"[pod/test-sts-0/test-container] test log content for pod test-sts-0\n",
"[pod/test-sts-1/test-container] test log content for pod test-sts-1\n",
},
},
{
name: "pod logs with prefix: init container",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
@ -105,7 +135,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Prefix = true
@ -127,7 +157,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Prefix = true
@ -159,7 +189,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
return o
@ -196,7 +226,7 @@ func TestLog(t *testing.T) {
}
wg.Add(3)
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Follow = true
@ -234,7 +264,7 @@ func TestLog(t *testing.T) {
}
wg.Add(3)
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.MaxFollowConcurrency = 2
@ -246,7 +276,7 @@ func TestLog(t *testing.T) {
{
name: "fail if LogsForObject fails",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = func(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration, allContainers bool) (map[corev1.ObjectReference]restclient.ResponseWrapper, error) {
return nil, errors.New("Error from the LogsForObject")
}
@ -272,9 +302,9 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = func(req restclient.ResponseWrapper, out io.Writer) error {
o.ConsumeRequestFn = func(ctx context.Context, req restclient.ResponseWrapper, out io.Writer) error {
return errors.New("Error from the ConsumeRequestFn")
}
return o
@ -307,7 +337,7 @@ func TestLog(t *testing.T) {
}
wg.Add(3)
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Follow = true
@ -346,9 +376,9 @@ func TestLog(t *testing.T) {
}
wg.Add(3)
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = func(req restclient.ResponseWrapper, out io.Writer) error {
o.ConsumeRequestFn = func(ctx context.Context, req restclient.ResponseWrapper, out io.Writer) error {
return errors.New("Error from the ConsumeRequestFn")
}
o.Follow = true
@ -369,9 +399,9 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = func(req restclient.ResponseWrapper, out io.Writer) error {
o.ConsumeRequestFn = func(ctx context.Context, req restclient.ResponseWrapper, out io.Writer) error {
return errors.New("Error from the ConsumeRequestFn")
}
o.Follow = true
@ -402,7 +432,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.IgnoreLogErrors = true
@ -432,7 +462,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
return o
@ -462,7 +492,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.IgnoreLogErrors = true
@ -493,7 +523,7 @@ func TestLog(t *testing.T) {
},
}
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LogsForObject = mock.mockLogsForObject
o.ConsumeRequestFn = mock.mockConsumeRequest
o.Follow = true
@ -564,7 +594,7 @@ func TestValidateLogOptions(t *testing.T) {
{
name: "since & since-time",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.SinceSeconds = time.Hour
o.SinceTime = "2006-01-02T15:04:05Z"
@ -582,7 +612,7 @@ func TestValidateLogOptions(t *testing.T) {
{
name: "negative since-time",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.SinceSeconds = -1 * time.Second
var err error
@ -599,7 +629,7 @@ func TestValidateLogOptions(t *testing.T) {
{
name: "negative limit-bytes",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.LimitBytes = -100
var err error
@ -616,7 +646,7 @@ func TestValidateLogOptions(t *testing.T) {
{
name: "negative tail",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.Tail = -100
var err error
@ -633,7 +663,8 @@ func TestValidateLogOptions(t *testing.T) {
{
name: "container name combined with --all-containers",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, true)
o := NewLogsOptions(streams)
o.AllContainers = true
o.Container = "my-container"
var err error
@ -650,7 +681,7 @@ func TestValidateLogOptions(t *testing.T) {
{
name: "container name combined with second argument",
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.Container = "my-container"
o.ContainerNameSpecified = true
@ -697,7 +728,7 @@ func TestLogComplete(t *testing.T) {
name: "One args case",
args: []string{"foo"},
opts: func(streams genericiooptions.IOStreams) *LogsOptions {
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.Selector = "foo"
return o
},
@ -777,7 +808,7 @@ func TestDefaultConsumeRequest(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
buf := &bytes.Buffer{}
err := DefaultConsumeRequest(test.request, buf)
err := DefaultConsumeRequest(context.TODO(), test.request, buf)
if err != nil && !strings.Contains(err.Error(), test.expectedErr) {
t.Errorf("%s: expected to find:\n\t%s\nfound:\n\t%s\n", test.name, test.expectedErr, err.Error())
@ -816,7 +847,7 @@ func TestNoResourceFoundMessage(t *testing.T) {
streams, _, buf, errbuf := genericiooptions.NewTestIOStreams()
cmd := NewCmdLogs(tf, streams)
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
o.Selector = "foo"
err := o.Complete(tf, cmd, []string{})
@ -864,7 +895,7 @@ func TestNoPodInNamespaceFoundMessage(t *testing.T) {
streams, _, _, _ := genericiooptions.NewTestIOStreams()
cmd := NewCmdLogs(tf, streams)
o := NewLogsOptions(streams, false)
o := NewLogsOptions(streams)
err := o.Complete(tf, cmd, []string{podName})
if err == nil {
@ -901,8 +932,8 @@ type logTestMock struct {
wg *sync.WaitGroup
}
func (l *logTestMock) mockConsumeRequest(request restclient.ResponseWrapper, out io.Writer) error {
readCloser, err := request.Stream(context.Background())
func (l *logTestMock) mockConsumeRequest(ctx context.Context, request restclient.ResponseWrapper, out io.Writer) error {
readCloser, err := request.Stream(ctx)
if err != nil {
return err
}
@ -919,6 +950,13 @@ func (l *logTestMock) mockConsumeRequest(request restclient.ResponseWrapper, out
func (l *logTestMock) mockLogsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration, allContainers bool) (map[corev1.ObjectReference]restclient.ResponseWrapper, error) {
switch object.(type) {
case *appsv1.Deployment:
_, ok := options.(*corev1.PodLogOptions)
if !ok {
return nil, errors.New("provided options object is not a PodLogOptions")
}
return l.logsForObjectRequests, nil
case *corev1.Pod:
_, ok := options.(*corev1.PodLogOptions)
if !ok {

View File

@ -22,9 +22,8 @@ import (
"reflect"
"strings"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
"github.com/spf13/cobra"
jsonpatch "gopkg.in/evanphx/json-patch.v4"
"k8s.io/klog/v2"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -45,7 +44,6 @@ import (
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/completion"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/slice"
"k8s.io/kubectl/pkg/util/templates"
)
@ -107,8 +105,6 @@ var (
kubectl patch deployment nginx-deployment --subresource='scale' --type='merge' -p '{"spec":{"replicas":2}}'`))
)
var supportedSubresources = []string{"status", "scale"}
func NewPatchOptions(ioStreams genericiooptions.IOStreams) *PatchOptions {
return &PatchOptions{
RecordFlags: genericclioptions.NewRecordFlags(),
@ -140,12 +136,12 @@ 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.StringKeySet(patchTypes).List()))
cmd.Flags().StringVar(&o.PatchType, "type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.List(sets.KeySet(patchTypes))))
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.")
cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-patch")
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, patch will operate on the subresource of the requested object.", supportedSubresources...)
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, patch will operate on the subresource of the requested object.")
return cmd
}
@ -197,12 +193,9 @@ 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.StringKeySet(patchTypes).List(), o.PatchType)
return fmt.Errorf("--type must be one of %v, not %q", sets.List(sets.KeySet(patchTypes)), o.PatchType)
}
}
if len(o.Subresource) > 0 && !slice.ContainsString(supportedSubresources, o.Subresource, nil) {
return fmt.Errorf("invalid subresource value: %q. Must be one of %v", o.Subresource, supportedSubresources)
}
return nil
}
@ -266,7 +259,7 @@ func (o *PatchOptions) RunPatch() error {
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes, nil)
if err != nil {
if apierrors.IsUnsupportedMediaType(err) {
return errors.Wrap(err, fmt.Sprintf("%s is not supported by %s", patchType, mapping.GroupVersionKind))
return fmt.Errorf("%s is not supported by %s: %w", patchType, mapping.GroupVersionKind, err)
}
return err
}

View File

@ -40,15 +40,19 @@ var (
Plugins provide extended functionality that is not part of the major command-line distribution.
Please refer to the documentation and examples for more information about how write your own plugins.
The easiest way to discover and install plugins is via the kubernetes sub-project krew.
To install krew, visit [krew.sigs.k8s.io](https://krew.sigs.k8s.io/docs/user-guide/setup/install/)`))
The easiest way to discover and install plugins is via the kubernetes sub-project krew: [krew.sigs.k8s.io].
To install krew, visit https://krew.sigs.k8s.io/docs/user-guide/setup/install`))
pluginExample = templates.Examples(i18n.T(`
# List all available plugins
kubectl plugin list`))
kubectl plugin list
# List only binary names of available plugins without paths
kubectl plugin list --name-only`))
pluginListLong = templates.LongDesc(i18n.T(`
List all available plugin files on a user's PATH.
To see plugins binary names without the full path use --name-only flag.
Available plugin files are those that are:
- executable
@ -65,6 +69,7 @@ func NewCmdPlugin(streams genericiooptions.IOStreams) *cobra.Command {
DisableFlagsInUseLine: true,
Short: i18n.T("Provides utilities for interacting with plugins"),
Long: pluginLong,
Example: pluginExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.DefaultSubCommandRun(streams.ErrOut)(cmd, args)
},

View File

@ -107,7 +107,7 @@ func NewCmdPortForward(f cmdutil.Factory, streams genericiooptions.IOStreams) *c
Short: i18n.T("Forward one or more local ports to a pod"),
Long: portforwardLong,
Example: portforwardExample,
ValidArgsFunction: completion.PodResourceNameCompletionFunc(f),
ValidArgsFunction: completion.ResourceAndPortCompletionFunc(f),
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(opts.Complete(f, cmd, args))
cmdutil.CheckErr(opts.Validate())
@ -136,19 +136,29 @@ type defaultPortForwarder struct {
genericiooptions.IOStreams
}
func (f *defaultPortForwarder) ForwardPorts(method string, url *url.URL, opts PortForwardOptions) error {
func createDialer(method string, url *url.URL, opts PortForwardOptions) (httpstream.Dialer, error) {
transport, upgrader, err := spdy.RoundTripperFor(opts.Config)
if err != nil {
return err
return nil, err
}
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, method, url)
if cmdutil.PortForwardWebsockets.IsEnabled() {
if !cmdutil.PortForwardWebsockets.IsDisabled() {
tunnelingDialer, err := portforward.NewSPDYOverWebsocketDialer(url, opts.Config)
if err != nil {
return err
return nil, err
}
// First attempt tunneling (websocket) dialer, then fallback to spdy dialer.
dialer = portforward.NewFallbackDialer(tunnelingDialer, dialer, httpstream.IsUpgradeFailure)
dialer = portforward.NewFallbackDialer(tunnelingDialer, dialer, func(err error) bool {
return httpstream.IsUpgradeFailure(err) || httpstream.IsHTTPSProxyError(err)
})
}
return dialer, nil
}
func (f *defaultPortForwarder) ForwardPorts(method string, url *url.URL, opts PortForwardOptions) error {
dialer, err := createDialer(method, url, opts)
if err != nil {
return err
}
fw, err := portforward.NewOnAddresses(dialer, opts.Address, opts.Ports, opts.StopChannel, opts.ReadyChannel, f.Out, f.ErrOut)
if err != nil {
@ -213,7 +223,9 @@ func convertPodNamedPortToNumber(ports []string, pod corev1.Pod) ([]string, erro
var converted []string
for _, port := range ports {
localPort, remotePort := splitPort(port)
if remotePort == "" {
return nil, fmt.Errorf("remote port cannot be empty")
}
containerPortStr := remotePort
_, err := strconv.Atoi(remotePort)
if err != nil {
@ -235,7 +247,7 @@ func convertPodNamedPortToNumber(ports []string, pod corev1.Pod) ([]string, erro
return converted, nil
}
func checkUDPPorts(udpOnlyPorts sets.Int, ports []string, obj metav1.Object) error {
func checkUDPPorts(udpOnlyPorts sets.Set[int], ports []string, obj metav1.Object) error {
for _, port := range ports {
_, remotePort := splitPort(port)
portNum, err := strconv.Atoi(remotePort)
@ -269,8 +281,8 @@ func checkUDPPorts(udpOnlyPorts sets.Int, ports []string, obj metav1.Object) err
// 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.NewInt()
tcpPorts := sets.NewInt()
udpPorts := sets.New[int]()
tcpPorts := sets.New[int]()
for _, port := range svc.Spec.Ports {
portNum := int(port.Port)
switch port.Protocol {
@ -286,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.NewInt()
tcpPorts := sets.NewInt()
udpPorts := sets.New[int]()
tcpPorts := sets.New[int]()
for _, ct := range pod.Spec.Containers {
for _, ctPort := range ct.Ports {
portNum := int(ctPort.ContainerPort)
@ -321,7 +333,7 @@ func (o *PortForwardOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
getPodTimeout, err := cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return cmdutil.UsageErrorf(cmd, err.Error())
return cmdutil.UsageErrorf(cmd, "%s", err.Error())
}
resourceName := args[0]

View File

@ -32,7 +32,9 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/portforward"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
)
@ -818,6 +820,24 @@ func TestConvertPodNamedPortToNumber(t *testing.T) {
ports: []string{"https", "http"},
err: true,
},
{
name: "empty port name",
pod: corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Ports: []corev1.ContainerPort{
{
ContainerPort: int32(27017)},
},
},
},
},
},
ports: []string{"28015:"},
converted: nil,
err: true,
},
}
for _, tc := range cases {
@ -983,3 +1003,38 @@ func TestCheckUDPPort(t *testing.T) {
}
}
}
func TestCreateDialer(t *testing.T) {
url, err := url.Parse("http://localhost:8080/index.html")
if err != nil {
t.Fatalf("unable to parse test url: %v", err)
}
config := cmdtesting.DefaultClientConfig()
opts := PortForwardOptions{Config: config}
// First, ensure that no environment variable creates the fallback dialer.
dialer, err := createDialer("GET", url, opts)
if err != nil {
t.Fatalf("unable to create dialer: %v", err)
}
if _, isFallback := dialer.(*portforward.FallbackDialer); !isFallback {
t.Errorf("expected fallback dialer, got %#v", dialer)
}
// Next, check turning on feature flag explicitly also creates fallback dialer.
t.Setenv(string(cmdutil.PortForwardWebsockets), "true")
dialer, err = createDialer("GET", url, opts)
if err != nil {
t.Fatalf("unable to create dialer: %v", err)
}
if _, isFallback := dialer.(*portforward.FallbackDialer); !isFallback {
t.Errorf("expected fallback dialer, got %#v", dialer)
}
// Finally, check explicit disabling does NOT create the fallback dialer.
t.Setenv(string(cmdutil.PortForwardWebsockets), "false")
dialer, err = createDialer("GET", url, opts)
if err != nil {
t.Fatalf("unable to create dialer: %v", err)
}
if _, isFallback := dialer.(*portforward.FallbackDialer); isFallback {
t.Errorf("expected fallback dialer, got %#v", dialer)
}
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package replace
import (
"context"
"fmt"
"net/url"
"os"
@ -40,7 +41,6 @@ import (
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/slice"
"k8s.io/kubectl/pkg/util/templates"
"k8s.io/kubectl/pkg/validation"
)
@ -68,8 +68,6 @@ var (
kubectl replace --force -f ./pod.json`))
)
var supportedSubresources = []string{"status", "scale"}
type ReplaceOptions struct {
PrintFlags *genericclioptions.PrintFlags
RecordFlags *genericclioptions.RecordFlags
@ -136,7 +134,7 @@ func NewCmdReplace(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to PUT to the server. Uses the transport specified by the kubeconfig file.")
cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-replace")
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, replace will operate on the subresource of the requested object.", supportedSubresources...)
cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, replace will operate on the subresource of the requested object.")
return cmd
}
@ -249,10 +247,6 @@ func (o *ReplaceOptions) Validate() error {
}
}
if len(o.Subresource) > 0 && !slice.ContainsString(supportedSubresources, o.Subresource, nil) {
return fmt.Errorf("invalid subresource value: %q. Must be one of %v", o.Subresource, supportedSubresources)
}
return nil
}
@ -365,8 +359,7 @@ func (o *ReplaceOptions) forceReplace() error {
if err != nil {
return err
}
return wait.PollImmediate(1*time.Second, timeout, func() (bool, error) {
return wait.PollUntilContextTimeout(context.Background(), 1*time.Second, timeout, true, func(ctx context.Context) (bool, error) {
if err := info.Get(); !errors.IsNotFound(err) {
return false, err
}

View File

@ -105,7 +105,7 @@ func NewCmdRolloutHistory(f cmdutil.Factory, streams genericiooptions.IOStreams)
return cmd
}
// Complete completes al the required options
// Complete completes all the required options
func (o *RolloutHistoryOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.Resources = args
@ -177,7 +177,15 @@ func (o *RolloutHistoryOptions) Run() error {
}
if o.Revision > 0 {
printer.PrintObj(historyInfo[o.Revision], o.Out)
// 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
}
} else {
sortedKeys := make([]int64, 0, len(historyInfo))
for k := range historyInfo {

View File

@ -280,15 +280,12 @@ func TestRolloutHistoryWithOutput(t *testing.T) {
"kind": "ReplicaSet",
"apiVersion": "apps/v1",
"metadata": {
"name": "rev2",
"creationTimestamp": null
"name": "rev2"
},
"spec": {
"selector": null,
"template": {
"metadata": {
"creationTimestamp": null
},
"metadata": {},
"spec": {
"containers": null
}
@ -305,13 +302,11 @@ func TestRolloutHistoryWithOutput(t *testing.T) {
expectedOutput: `apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
name: rev2
spec:
selector: null
template:
metadata:
creationTimestamp: null
metadata: {}
spec:
containers: null
status:
@ -323,13 +318,11 @@ status:
expectedOutput: `apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
name: rev1
spec:
selector: null
template:
metadata:
creationTimestamp: null
metadata: {}
spec:
containers: null
status:
@ -338,13 +331,11 @@ status:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
name: rev2
spec:
selector: null
template:
metadata:
creationTimestamp: null
metadata: {}
spec:
containers: null
status:
@ -401,6 +392,88 @@ 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

@ -63,7 +63,7 @@ var (
Resource rollout will be restarted.`))
restartExample = templates.Examples(`
# Restart all deployments in test-namespace namespace
# Restart all deployments in the test-namespace namespace
kubectl rollout restart deployment -n test-namespace
# Restart a deployment

View File

@ -167,22 +167,6 @@ func NewCmdRun(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Com
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout)
// Deprecate the cascade flag. If set, it has no practical effect since the created pod has no dependents.
// TODO: Remove the cascade flag from the run command in kubectl 1.29
cmd.Flags().MarkDeprecated("cascade", "because it is not relevant for this command. It will be removed in version 1.29.")
// Deprecate and hide unused flags.
// These flags are being added to the run command by DeleteFlags to support pod deletion after attach,
// but they are not used if set, so they effectively do nothing.
// TODO: Remove these flags from the run command in kubectl 1.29
cmd.Flags().MarkDeprecated("filename", "because it is not used by this command. It will be removed in version 1.29.")
cmd.Flags().MarkDeprecated("force", "because it is not used by this command. It will be removed in version 1.29.")
cmd.Flags().MarkDeprecated("grace-period", "because it is not used by this command. It will be removed in version 1.29.")
cmd.Flags().MarkDeprecated("kustomize", "because it is not used by this command. It will be removed in version 1.29.")
cmd.Flags().MarkDeprecated("recursive", "because it is not used by this command. It will be removed in version 1.29.")
cmd.Flags().MarkDeprecated("timeout", "because it is not used by this command. It will be removed in version 1.29.")
cmd.Flags().MarkDeprecated("wait", "because it is not used by this command. It will be removed in version 1.29.")
return cmd
}
@ -520,7 +504,7 @@ func logOpts(restClientGetter genericclioptions.RESTClientGetter, pod *corev1.Po
return err
}
for _, request := range requests {
if err := logs.DefaultConsumeRequest(request, opts.Out); err != nil {
if err := logs.DefaultConsumeRequest(context.Background(), request, opts.Out); err != nil {
return err
}
}

View File

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

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