├── .github └── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── LICENSE ├── OWNERS ├── README.md ├── SECURITY_CONTACTS ├── cmd └── kubectl-ns.go ├── code-of-conduct.md ├── doc.go ├── go.mod ├── go.sum ├── kubectl_complete-ns └── pkg └── cmd └── ns.go /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Sorry, we do not accept changes directly against this repository. Please see 2 | CONTRIBUTING.md for information on where and how to contribute instead. 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing guidelines 2 | 3 | Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. 4 | 5 | This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/sample-cli-plugin](https://git.k8s.io/kubernetes/staging/src/k8s.io/sample-cli-plugin) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). 6 | 7 | Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - deads2k 5 | - pwittrock 6 | - seans3 7 | - soltysh 8 | - eddiezane 9 | - brianpursley 10 | - KnVerey 11 | reviewers: 12 | - deads2k 13 | - pwittrock 14 | - seans3 15 | - soltysh 16 | - eddiezane 17 | - brianpursley 18 | - KnVerey 19 | labels: 20 | - sig/cli 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sample-cli-plugin 2 | 3 | This repository implements a single kubectl plugin for switching the namespace 4 | that the current KUBECONFIG context points to. In order to remain as indestructive 5 | as possible, no existing contexts are modified. 6 | 7 | **Note:** go-get or vendor this package as `k8s.io/sample-cli-plugin`. 8 | 9 | This particular example demonstrates how to perform basic operations such as: 10 | 11 | * How to create a new custom command that follows kubectl patterns 12 | * How to obtain a user's KUBECONFIG settings and modify them 13 | * How to make general use of the provided "cli-runtime" set of helpers for kubectl and third-party plugins 14 | 15 | It makes use of the genericclioptions in [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) 16 | to generate a set of configuration flags which are in turn used to generate a raw representation of 17 | the user's KUBECONFIG, as well as to obtain configuration which can be used with RESTClients when sending 18 | requests to a kubernetes api server. 19 | 20 | ## Details 21 | 22 | The sample cli plugin uses the [client-go library](https://github.com/kubernetes/client-go/tree/master/tools/clientcmd) to patch an existing KUBECONFIG file in a user's environment in order to update context information to point the client to a new or existing namespace. 23 | 24 | In order to be as non-destructive as possible, no existing contexts are modified in any way. Rather, the current context is examined, and matched against existing contexts to find a context containing the same "AuthInfo" and "Cluster" information, but with the newly desired namespace requested by the user. 25 | 26 | ## Purpose 27 | 28 | This is an example of how to build a kubectl plugin using the same set of tools and helpers available to kubectl. 29 | 30 | ## Running 31 | 32 | ```sh 33 | # assumes you have a working KUBECONFIG 34 | $ go build cmd/kubectl-ns.go 35 | # place the built binary somewhere in your PATH 36 | $ cp ./kubectl-ns /usr/local/bin 37 | 38 | # you can now begin using this plugin as a regular kubectl command: 39 | # update your configuration to point to "new-namespace" 40 | $ kubectl ns new-namespace 41 | # any kubectl commands you perform from now on will use "new-namespace" 42 | $ kubectl get pod 43 | NAME READY STATUS RESTARTS AGE 44 | new-namespace-pod 1/1 Running 0 1h 45 | 46 | # list all of the namespace in use by contexts in your KUBECONFIG 47 | $ kubectl ns --list 48 | 49 | # show the namespace that the currently set context in your KUBECONFIG points to 50 | $ kubectl ns 51 | ``` 52 | 53 | ## Use Cases 54 | 55 | This plugin can be used as a developer tool, in order to quickly view or change the current namespace 56 | that kubectl points to. 57 | 58 | It can also be used as a means of showcasing usage of the cli-runtime set of utilities to aid in 59 | third-party plugin development. 60 | 61 | ## Shell completion 62 | 63 | This plugin supports shell completion when used through kubectl. To enable shell completion for the plugin 64 | you must copy the file `./kubectl_complete-ns` somewhere on `$PATH` and give it executable permissions. 65 | 66 | The `./kubectl_complete-ns` script shows a hybrid approach to providing completions: 67 | 1. it uses the builtin `__complete` command provided by [Cobra](https://github.com/spf13/cobra) for flags 68 | 1. it calls `kubectl` to obtain the list of namespaces to complete arguments (note that a more elegant approach would be to have the `kubectl-ns` program itself provide completion of arguments by implementing Cobra's `ValidArgsFunction` to fetch the list of namespaces, but it would then be a less varied example) 69 | 70 | One can then do things like: 71 | ``` 72 | $ kubectl ns 73 | default kube-node-lease kube-public kube-system 74 | 75 | $ kubectl ns -- 76 | --as -- Username to impersonate for the operation. User could be a regular user or a service account in a namespace. 77 | --as-group -- Group to impersonate for the operation, this flag can be repeated to specify multiple groups. 78 | --as-uid -- UID to impersonate for the operation. 79 | --cache-dir -- Default cache directory 80 | [...] 81 | ``` 82 | 83 | Note: kubectl v1.26 or higher is required for shell completion to work for plugins. 84 | ## Cleanup 85 | 86 | You can "uninstall" this plugin from kubectl by simply removing it from your PATH: 87 | 88 | $ rm /usr/local/bin/kubectl-ns 89 | 90 | ## Compatibility 91 | 92 | HEAD of this repository will match HEAD of k8s.io/apimachinery and 93 | k8s.io/client-go. 94 | 95 | ## Where does it come from? 96 | 97 | `sample-cli-plugin` is synced from 98 | https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/sample-cli-plugin. 99 | Code changes are made in that location, merged into k8s.io/kubernetes and 100 | later synced here. 101 | 102 | -------------------------------------------------------------------------------- /SECURITY_CONTACTS: -------------------------------------------------------------------------------- 1 | # Defined below are the security contacts for this repo. 2 | # 3 | # They are the contact point for the Product Security Committee to reach out 4 | # to for triaging and handling of incoming issues. 5 | # 6 | # The below names agree to abide by the 7 | # [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) 8 | # and will be removed and replaced if they violate that agreement. 9 | # 10 | # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE 11 | # INSTRUCTIONS AT https://kubernetes.io/security/ 12 | 13 | ardaguclu 14 | eddiezane 15 | mpuckett159 16 | soltysh 17 | -------------------------------------------------------------------------------- /cmd/kubectl-ns.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "os" 21 | 22 | "github.com/spf13/pflag" 23 | 24 | "k8s.io/cli-runtime/pkg/genericiooptions" 25 | "k8s.io/sample-cli-plugin/pkg/cmd" 26 | ) 27 | 28 | func main() { 29 | flags := pflag.NewFlagSet("kubectl-ns", pflag.ExitOnError) 30 | pflag.CommandLine = flags 31 | 32 | root := cmd.NewCmdNamespace(genericiooptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}) 33 | if err := root.Execute(); err != nil { 34 | os.Exit(1) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Community Code of Conduct 2 | 3 | Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package samplecliplugin 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // This is a generated file. Do not edit directly. 2 | 3 | module k8s.io/sample-cli-plugin 4 | 5 | go 1.24.0 6 | 7 | godebug default=go1.24 8 | 9 | require ( 10 | github.com/spf13/cobra v1.8.1 11 | github.com/spf13/pflag v1.0.6 12 | k8s.io/cli-runtime v0.0.0-20250528181011-72dcb30dbed5 13 | k8s.io/client-go v0.0.0-20250526134158-e75871c73119 14 | ) 15 | 16 | require ( 17 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect 18 | github.com/blang/semver/v4 v4.0.0 // indirect 19 | github.com/davecgh/go-spew v1.1.1 // indirect 20 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 21 | github.com/fxamacker/cbor/v2 v2.8.0 // indirect 22 | github.com/go-errors/errors v1.4.2 // indirect 23 | github.com/go-logr/logr v1.4.2 // indirect 24 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 25 | github.com/go-openapi/jsonreference v0.20.2 // indirect 26 | github.com/go-openapi/swag v0.23.0 // indirect 27 | github.com/gogo/protobuf v1.3.2 // indirect 28 | github.com/google/btree v1.1.3 // indirect 29 | github.com/google/gnostic-models v0.6.9 // indirect 30 | github.com/google/go-cmp v0.7.0 // indirect 31 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect 32 | github.com/google/uuid v1.6.0 // indirect 33 | github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect 34 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 35 | github.com/josharian/intern v1.0.0 // indirect 36 | github.com/json-iterator/go v1.1.12 // indirect 37 | github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect 38 | github.com/mailru/easyjson v0.7.7 // indirect 39 | github.com/moby/term v0.5.0 // indirect 40 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 41 | github.com/modern-go/reflect2 v1.0.2 // indirect 42 | github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect 43 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 44 | github.com/peterbourgon/diskv v2.0.1+incompatible // indirect 45 | github.com/pkg/errors v0.9.1 // indirect 46 | github.com/x448/float16 v0.8.4 // indirect 47 | github.com/xlab/treeprint v1.2.0 // indirect 48 | golang.org/x/net v0.38.0 // indirect 49 | golang.org/x/oauth2 v0.27.0 // indirect 50 | golang.org/x/sync v0.12.0 // indirect 51 | golang.org/x/sys v0.31.0 // indirect 52 | golang.org/x/term v0.30.0 // indirect 53 | golang.org/x/text v0.23.0 // indirect 54 | golang.org/x/time v0.9.0 // indirect 55 | google.golang.org/protobuf v1.36.5 // indirect 56 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 57 | gopkg.in/inf.v0 v0.9.1 // indirect 58 | gopkg.in/yaml.v3 v3.0.1 // indirect 59 | k8s.io/api v0.0.0-20250527173755-16b0005a085f // indirect 60 | k8s.io/apimachinery v0.0.0-20250527161416-09ff13941cda // indirect 61 | k8s.io/klog/v2 v2.130.1 // indirect 62 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect 63 | k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect 64 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 65 | sigs.k8s.io/kustomize/api v0.19.0 // indirect 66 | sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect 67 | sigs.k8s.io/randfill v1.0.0 // indirect 68 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect 69 | sigs.k8s.io/yaml v1.4.0 // indirect 70 | ) 71 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= 2 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 3 | github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= 4 | github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= 5 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 6 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 7 | github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= 8 | github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= 13 | github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 14 | github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= 15 | github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= 16 | github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= 17 | github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= 18 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 19 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 20 | github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= 21 | github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= 22 | github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= 23 | github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= 24 | github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= 25 | github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= 26 | github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= 27 | github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 28 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 29 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 30 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 31 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 32 | github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= 33 | github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= 34 | github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= 35 | github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= 36 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 37 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 38 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 39 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 40 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= 41 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 42 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= 43 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 44 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 45 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 46 | github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= 47 | github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 48 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 49 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 50 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 51 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 52 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 53 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 54 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 55 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 56 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 57 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 58 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 59 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 60 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 61 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 62 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 63 | github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= 64 | github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= 65 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 66 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 67 | github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= 68 | github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= 69 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 70 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 71 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 72 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 73 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 74 | github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= 75 | github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= 76 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 77 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 78 | github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= 79 | github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= 80 | github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= 81 | github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= 82 | github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= 83 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 84 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 85 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 86 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 87 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 88 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 89 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 90 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 91 | github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= 92 | github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 93 | github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= 94 | github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 95 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 96 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 97 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 98 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 99 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 100 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 101 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 102 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 103 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 104 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 105 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 106 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 107 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 108 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 109 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 110 | github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= 111 | github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 112 | github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= 113 | github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= 114 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 115 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 116 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 117 | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 118 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 119 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 120 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 121 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 122 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 123 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 124 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 125 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 126 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 127 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= 128 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 129 | golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= 130 | golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= 131 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 132 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 133 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 134 | golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= 135 | golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 136 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 137 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 138 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 139 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 140 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 141 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 142 | golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= 143 | golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= 144 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 145 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 146 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= 147 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 148 | golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= 149 | golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 150 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 151 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 152 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 153 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 154 | golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= 155 | golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 156 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 157 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 158 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 159 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 160 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= 161 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 162 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 163 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 164 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 165 | gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= 166 | gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= 167 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 168 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 169 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 170 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 171 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 172 | k8s.io/api v0.0.0-20250527173755-16b0005a085f h1:C0Bz4t9IabezajOCeqalSr1OL/ETPXGVozwlXWG5i84= 173 | k8s.io/api v0.0.0-20250527173755-16b0005a085f/go.mod h1:Aj27FjqgMbqUHz3RjW8DWFDeDjymt6ggPYO7yzawAVQ= 174 | k8s.io/apimachinery v0.0.0-20250527161416-09ff13941cda h1:3GHsiuK4HX0R/gZ53Q/c0Pa9pNlOL1IiY6esUBs1Ps4= 175 | k8s.io/apimachinery v0.0.0-20250527161416-09ff13941cda/go.mod h1:pJRnLHx/rdGhRBHKhKq/NczIcMw4cPylIe+hff1zJaU= 176 | k8s.io/cli-runtime v0.0.0-20250528181011-72dcb30dbed5 h1:76MDneRbSIMhMYLhOPFmMa0Y9SqdP4mLg/CPqemxPZE= 177 | k8s.io/cli-runtime v0.0.0-20250528181011-72dcb30dbed5/go.mod h1:yIaRy1SW+SkqHTuYSFBLs7a7b9+Zs98WYOQj6UijxHw= 178 | k8s.io/client-go v0.0.0-20250526134158-e75871c73119 h1:LQVcLhILJww2BUggii/Cj2YsF+5OS+jRtDdHTB+dq5U= 179 | k8s.io/client-go v0.0.0-20250526134158-e75871c73119/go.mod h1:70YvuiC0JxRnkbXLUExjxqfqaPzpA0RvkM0mUmvQ2Fo= 180 | k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= 181 | k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 182 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= 183 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= 184 | k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg= 185 | k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 186 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= 187 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= 188 | sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ= 189 | sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o= 190 | sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA= 191 | sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY= 192 | sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= 193 | sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= 194 | sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= 195 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= 196 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= 197 | sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= 198 | sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 199 | -------------------------------------------------------------------------------- /kubectl_complete-ns: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # If we are completing a flag, use Cobra's builtin completion system. 4 | # To know if we are completing a flag we need the last argument starts with a `-` and does not contain an `=` 5 | args=("$@") 6 | lastArg=${args[((${#args[@]}-1))]} 7 | if [[ "$lastArg" == -* ]]; then 8 | if [[ "$lastArg" != *=* ]]; then 9 | kubectl ns __complete "$@" 10 | fi 11 | else 12 | # TODO Make sure we are not completing the value of a flag. 13 | # TODO Only complete a single argument. 14 | # Both are pretty hard to do in a shell script. The better way to do this would be to let 15 | # Cobra do all the completions by using `cobra.ValidArgsFunction` in the program. 16 | # But the below, although imperfect, is a nice example for plugins that don't use Cobra. 17 | 18 | # We are probably completing an argument. This plugin only accepts namespaces, let's fetch them. 19 | kubectl get namespaces --output go-template='{{ range .items }}{{ .metadata.name }}{{"\n"}}{{ end }}' 20 | 21 | # Turn off file completion. See the ShellCompDirective documentation within 22 | # https://github.com/spf13/cobra/blob/main/shell_completions.md#completion-of-nouns 23 | echo :4 24 | fi 25 | -------------------------------------------------------------------------------- /pkg/cmd/ns.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | "strings" 22 | 23 | "github.com/spf13/cobra" 24 | 25 | "k8s.io/client-go/tools/clientcmd" 26 | "k8s.io/client-go/tools/clientcmd/api" 27 | 28 | "k8s.io/cli-runtime/pkg/genericclioptions" 29 | "k8s.io/cli-runtime/pkg/genericiooptions" 30 | ) 31 | 32 | var ( 33 | namespaceExample = ` 34 | # view the current namespace in your KUBECONFIG 35 | %[1]s ns 36 | 37 | # view all of the namespaces in use by contexts in your KUBECONFIG 38 | %[1]s ns --list 39 | 40 | # switch your current-context to one that contains the desired namespace 41 | %[1]s ns foo 42 | ` 43 | 44 | errNoContext = fmt.Errorf("no context is currently set, use %q to select a new one", "kubectl config use-context ") 45 | ) 46 | 47 | // NamespaceOptions provides information required to update 48 | // the current context on a user's KUBECONFIG 49 | type NamespaceOptions struct { 50 | configFlags *genericclioptions.ConfigFlags 51 | 52 | resultingContext *api.Context 53 | resultingContextName string 54 | 55 | userSpecifiedCluster string 56 | userSpecifiedContext string 57 | userSpecifiedAuthInfo string 58 | userSpecifiedNamespace string 59 | 60 | rawConfig api.Config 61 | listNamespaces bool 62 | args []string 63 | 64 | genericiooptions.IOStreams 65 | } 66 | 67 | // NewNamespaceOptions provides an instance of NamespaceOptions with default values 68 | func NewNamespaceOptions(streams genericiooptions.IOStreams) *NamespaceOptions { 69 | return &NamespaceOptions{ 70 | configFlags: genericclioptions.NewConfigFlags(true), 71 | 72 | IOStreams: streams, 73 | } 74 | } 75 | 76 | // NewCmdNamespace provides a cobra command wrapping NamespaceOptions 77 | func NewCmdNamespace(streams genericiooptions.IOStreams) *cobra.Command { 78 | o := NewNamespaceOptions(streams) 79 | 80 | cmd := &cobra.Command{ 81 | Use: "ns [new-namespace] [flags]", 82 | Short: "View or set the current namespace", 83 | Example: fmt.Sprintf(namespaceExample, "kubectl"), 84 | SilenceUsage: true, 85 | Annotations: map[string]string{ 86 | cobra.CommandDisplayNameAnnotation: "kubectl ns", 87 | }, 88 | RunE: func(c *cobra.Command, args []string) error { 89 | if err := o.Complete(c, args); err != nil { 90 | return err 91 | } 92 | if err := o.Validate(); err != nil { 93 | return err 94 | } 95 | if err := o.Run(); err != nil { 96 | return err 97 | } 98 | 99 | return nil 100 | }, 101 | } 102 | 103 | cmd.Flags().BoolVar(&o.listNamespaces, "list", o.listNamespaces, "if true, print the list of all namespaces in the current KUBECONFIG") 104 | o.configFlags.AddFlags(cmd.Flags()) 105 | 106 | return cmd 107 | } 108 | 109 | // Complete sets all information required for updating the current context 110 | func (o *NamespaceOptions) Complete(cmd *cobra.Command, args []string) error { 111 | o.args = args 112 | 113 | var err error 114 | o.rawConfig, err = o.configFlags.ToRawKubeConfigLoader().RawConfig() 115 | if err != nil { 116 | return err 117 | } 118 | 119 | o.userSpecifiedNamespace, err = cmd.Flags().GetString("namespace") 120 | if err != nil { 121 | return err 122 | } 123 | if len(args) > 0 { 124 | if len(o.userSpecifiedNamespace) > 0 { 125 | return fmt.Errorf("cannot specify both a --namespace value and a new namespace argument") 126 | } 127 | 128 | o.userSpecifiedNamespace = args[0] 129 | } 130 | 131 | // if no namespace argument or flag value was specified, then there 132 | // is no need to generate a resulting context 133 | if len(o.userSpecifiedNamespace) == 0 { 134 | return nil 135 | } 136 | 137 | o.userSpecifiedContext, err = cmd.Flags().GetString("context") 138 | if err != nil { 139 | return err 140 | } 141 | 142 | o.userSpecifiedCluster, err = cmd.Flags().GetString("cluster") 143 | if err != nil { 144 | return err 145 | } 146 | 147 | o.userSpecifiedAuthInfo, err = cmd.Flags().GetString("user") 148 | if err != nil { 149 | return err 150 | } 151 | 152 | currentContext, exists := o.rawConfig.Contexts[o.rawConfig.CurrentContext] 153 | if !exists { 154 | return errNoContext 155 | } 156 | 157 | o.resultingContext = api.NewContext() 158 | o.resultingContext.Cluster = currentContext.Cluster 159 | o.resultingContext.AuthInfo = currentContext.AuthInfo 160 | 161 | // if a target context is explicitly provided by the user, 162 | // use that as our reference for the final, resulting context 163 | if len(o.userSpecifiedContext) > 0 { 164 | o.resultingContextName = o.userSpecifiedContext 165 | if userCtx, exists := o.rawConfig.Contexts[o.userSpecifiedContext]; exists { 166 | o.resultingContext = userCtx.DeepCopy() 167 | } 168 | } 169 | 170 | // override context info with user provided values 171 | o.resultingContext.Namespace = o.userSpecifiedNamespace 172 | 173 | if len(o.userSpecifiedCluster) > 0 { 174 | o.resultingContext.Cluster = o.userSpecifiedCluster 175 | } 176 | if len(o.userSpecifiedAuthInfo) > 0 { 177 | o.resultingContext.AuthInfo = o.userSpecifiedAuthInfo 178 | } 179 | 180 | // generate a unique context name based on its new values if 181 | // user did not explicitly request a context by name 182 | if len(o.userSpecifiedContext) == 0 { 183 | o.resultingContextName = generateContextName(o.resultingContext) 184 | } 185 | 186 | return nil 187 | } 188 | 189 | func generateContextName(fromContext *api.Context) string { 190 | name := fromContext.Namespace 191 | if len(fromContext.Cluster) > 0 { 192 | name = fmt.Sprintf("%s/%s", name, fromContext.Cluster) 193 | } 194 | if len(fromContext.AuthInfo) > 0 { 195 | cleanAuthInfo := strings.Split(fromContext.AuthInfo, "/")[0] 196 | name = fmt.Sprintf("%s/%s", name, cleanAuthInfo) 197 | } 198 | 199 | return name 200 | } 201 | 202 | // Validate ensures that all required arguments and flag values are provided 203 | func (o *NamespaceOptions) Validate() error { 204 | if len(o.rawConfig.CurrentContext) == 0 { 205 | return errNoContext 206 | } 207 | if len(o.args) > 1 { 208 | return fmt.Errorf("either one or no arguments are allowed") 209 | } 210 | 211 | return nil 212 | } 213 | 214 | // Run lists all available namespaces on a user's KUBECONFIG or updates the 215 | // current context based on a provided namespace. 216 | func (o *NamespaceOptions) Run() error { 217 | if len(o.userSpecifiedNamespace) > 0 && o.resultingContext != nil { 218 | return o.setNamespace(o.resultingContext, o.resultingContextName) 219 | } 220 | 221 | namespaces := map[string]bool{} 222 | 223 | for name, c := range o.rawConfig.Contexts { 224 | if !o.listNamespaces && name == o.rawConfig.CurrentContext { 225 | if len(c.Namespace) == 0 { 226 | return fmt.Errorf("no namespace is set for your current context: %q", name) 227 | } 228 | 229 | fmt.Fprintf(o.Out, "%s\n", c.Namespace) 230 | return nil 231 | } 232 | 233 | // skip if dealing with a namespace we have already seen 234 | // or if the namespace for the current context is empty 235 | if len(c.Namespace) == 0 { 236 | continue 237 | } 238 | if namespaces[c.Namespace] { 239 | continue 240 | } 241 | 242 | namespaces[c.Namespace] = true 243 | } 244 | 245 | if !o.listNamespaces { 246 | return fmt.Errorf("unable to find information for the current namespace in your configuration") 247 | } 248 | 249 | for n := range namespaces { 250 | fmt.Fprintf(o.Out, "%s\n", n) 251 | } 252 | 253 | return nil 254 | } 255 | 256 | func isContextEqual(ctxA, ctxB *api.Context) bool { 257 | if ctxA == nil || ctxB == nil { 258 | return false 259 | } 260 | if ctxA.Cluster != ctxB.Cluster { 261 | return false 262 | } 263 | if ctxA.Namespace != ctxB.Namespace { 264 | return false 265 | } 266 | if ctxA.AuthInfo != ctxB.AuthInfo { 267 | return false 268 | } 269 | 270 | return true 271 | } 272 | 273 | // setNamespace receives a "desired" context state and determines if a similar context 274 | // is already present in a user's KUBECONFIG. If one is not, then a new context is added 275 | // to the user's config under the provided destination name. 276 | // The current context field is updated to point to the new context. 277 | func (o *NamespaceOptions) setNamespace(fromContext *api.Context, withContextName string) error { 278 | if len(fromContext.Namespace) == 0 { 279 | return fmt.Errorf("a non-empty namespace must be provided") 280 | } 281 | 282 | configAccess := clientcmd.NewDefaultPathOptions() 283 | 284 | // determine if we have already saved this context to the user's KUBECONFIG before 285 | // if so, simply switch the current context to the existing one. 286 | if existingResultingCtx, exists := o.rawConfig.Contexts[withContextName]; !exists || !isContextEqual(fromContext, existingResultingCtx) { 287 | o.rawConfig.Contexts[withContextName] = fromContext 288 | } 289 | o.rawConfig.CurrentContext = withContextName 290 | 291 | fmt.Fprintf(o.Out, "namespace changed to %q\n", fromContext.Namespace) 292 | return clientcmd.ModifyConfig(configAccess, o.rawConfig, true) 293 | } 294 | --------------------------------------------------------------------------------