Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Factory
kubectl-dup
kubectl-dup-0.3.2.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kubectl-dup-0.3.2.obscpio of Package kubectl-dup
07070100000000000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000001A00000000kubectl-dup-0.3.2/.github07070100000001000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000002400000000kubectl-dup-0.3.2/.github/workflows07070100000002000081A400000000000000000000000166C10ABB0000023B000000000000000000000000000000000000003000000000kubectl-dup-0.3.2/.github/workflows/release.ymlname: release on: push: tags: - 'v*.*.*' jobs: goreleaser: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@master - name: Setup Go uses: actions/setup-go@v5 - name: GoReleaser uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser version: '~> v2' args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Update new version in krew-index uses: rajatjindal/krew-release-bot@v0.0.46 07070100000003000081A400000000000000000000000166C10ABB000001ED000000000000000000000000000000000000001D00000000kubectl-dup-0.3.2/.gitignore# If you prefer the allow list template instead of the deny list, see community template: # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib /bin/* /dist/* # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ # Go workspace file go.work 07070100000004000081A400000000000000000000000166C10ABB000002E8000000000000000000000000000000000000002200000000kubectl-dup-0.3.2/.goreleaser.ymlversion: 2 before: hooks: - go mod tidy builds: - env: - CGO_ENABLED=0 goos: - linux - darwin - windows goarch: - amd64 - arm64 ignore: - goos: windows goarch: arm64 mod_timestamp: "{{ .CommitTimestamp }}" binary: kubectl-dup ldflags: - -s -w checksum: name_template: "{{ .ProjectName }}_{{ .Tag }}_checksums.txt" archives: - format: tar.gz name_template: "{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" # use zip for windows archives format_overrides: - goos: windows format: zip changelog: use: github snapshot: version_template: "{{ incminor .Tag }}-dev-{{ .ShortCommit }}" 07070100000005000081A400000000000000000000000166C10ABB00000624000000000000000000000000000000000000001D00000000kubectl-dup-0.3.2/.krew.yamlapiVersion: krew.googlecontainertools.github.com/v1alpha2 kind: Plugin metadata: name: dup spec: version: {{ .TagName }} homepage: https://github.com/vash/dup shortDescription: Duplicate existing Kubernetes resources description: | This plugin is designed for on-the-fly duplication of Kubernetes resources. It focuses on providing a convenient way to edit resources before duplication, with a specific emphasis on Pods to create a fine-tuned resource quickly. This tool can be used for debugging running containers without them crashing, and simplifying the administration and general interaction with Kubernetes clusters. platforms: - selector: matchLabels: os: darwin arch: amd64 {{addURIAndSha "https://github.com/vash/dup/releases/download/{{ .TagName }}/dup_{{ .TagName }}_darwin_amd64.tar.gz" .TagName }} bin: kubectl-dup - selector: matchLabels: os: darwin arch: arm64 {{addURIAndSha "https://github.com/vash/dup/releases/download/{{ .TagName }}/dup_{{ .TagName }}_darwin_arm64.tar.gz" .TagName }} bin: kubectl-dup - selector: matchLabels: os: linux arch: amd64 {{addURIAndSha "https://github.com/vash/dup/releases/download/{{ .TagName }}/dup_{{ .TagName }}_linux_amd64.tar.gz" .TagName }} bin: kubectl-dup - selector: matchLabels: os: windows arch: amd64 {{addURIAndSha "https://github.com/vash/dup/releases/download/{{ .TagName }}/dup_{{ .TagName }}_windows_amd64.zip" .TagName }} bin: kubectl-dup.exe 07070100000006000081A400000000000000000000000166C10ABB0000042E000000000000000000000000000000000000001A00000000kubectl-dup-0.3.2/LICENSEMIT License Copyright (c) 2024 Eliran Barnoy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 07070100000007000081A400000000000000000000000166C10ABB0000081D000000000000000000000000000000000000001C00000000kubectl-dup-0.3.2/README.md![Dup](imgs/dup.svg) # dup - kubectl Plugin for duplication of Kubernetes Resources This plugin is designed for on-the-fly duplication of Kubernetes resources. It focuses on providing a convenient way to edit resources before duplication, with a specific emphasis on Pods to create a fine-tuned resource quickly. This tool can be used for debugging running containers without them crashing, and simplifying the administration and general interaction with Kubernetes clusters. [![asciicast](https://asciinema.org/a/C8Lr4dCXGOCA6Pc0GB7xXWSyG.svg)](https://asciinema.org/a/C8Lr4dCXGOCA6Pc0GB7xXWSyG) ## Installation ### Using Krew (Kubectl Plugin Manager) ```bash kubectl krew install dup ``` ### Manual Installation Download the latest release from the GitHub releases page. Extract the binary from the archive. Move the binary to a directory in your system's PATH. ### Usage ```bash kubectl dup [options] <resource-type,resource-type-2> <resource-name> <generated-resource-name-prefix> ``` ## Examples ```bash # duplicate a pod of deployment "my-deployment" without opening edit window kubectl dup deployment my-deployment -pk # duplicate a specific pod, regardless of what it belongs to, # and disable liveness probes on it. kubectl dup pod my-pod -d ``` ## Features - Resource Duplication: Duplicate Kubernetes resources with ease. - Interactive Editing: Open resources for manual editing before applying changes. - Pod Focused: Designed to streamline debugging and administration of Pods. ## Options - -d, --disable-probes Automatically disable readiness and liveness probes for duplicated pods. - -h, --help: Display help information. - -p, --pod: Duplicate pod of complex objects, supported objects: 'StatefulSet','Deployment','CronJob','Job'. - -k, --skip-edit: Skip editing duplicated resource before creation ## Contributing We welcome contributions! If you have any ideas, enhancements, or bug fixes, feel free to open an issue or submit a pull request. ## License This project is licensed under the MIT License - see the LICENSE file for details. 07070100000008000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000001600000000kubectl-dup-0.3.2/cmd07070100000009000081A400000000000000000000000166C10ABB00000A1E000000000000000000000000000000000000001E00000000kubectl-dup-0.3.2/cmd/root.gopackage cmd import ( "errors" "fmt" "dup/pkg/editor" "dup/pkg/util" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/completion" ) var ( kubeconfig string namespace string deployment string edit bool SilentErr = errors.New("SilentErr") ) func validateArgs(cmd *cobra.Command, args []string) error { if len(args) < 1 || len(args) > 2 { return fmt.Errorf("requires exactly 1 or 2 arguments") } for _, arg := range args { if !util.IsValidPod(arg) { return fmt.Errorf("invalid argument: %s", arg) } } return nil } func NewRootCmd(ioStreams genericclioptions.IOStreams) *cobra.Command { o := editor.NewEditOptions(ioStreams) kubeConfigFlags := defaultConfigFlags().WithWarningPrinter(o.IOStreams) matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags) f := cmdutil.NewFactory(matchVersionKubeConfigFlags) var rootCmd = &cobra.Command{ Use: "kubectl dup [options] <resource-type, ...resource-type-n> <resource> [output-resource-prefix]", Short: "Duplicate a pod out of a Deployment", ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), Args: cobra.RangeArgs(2, 3), Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Complete(f, args, cmd)) cmdutil.CheckErr(o.Run()) }, } rootCmd.Flags().BoolVarP(&o.DuplicateOptions.DuplicateInnerPod, "pod", "p", false, "Duplicate pod of resource, currently only applies for: 'StatefulSet','Deployment','CronJob','Job'") rootCmd.Flags().BoolVarP(&o.DuplicateOptions.DisableProbes, "disable-probes", "d", true, "Disable Readiness and liveness probes for duplicated pods only (requires '-p' for complex resources)") rootCmd.Flags().BoolVarP(&o.DuplicateOptions.LoopCommand, "command-loop", "l", false, "Changes running command to an infinite loop (currently : \"tail -f /dev/null\"") rootCmd.Flags().BoolVarP(&o.SkipEdit, "skip-edit", "k", false, "Skip editing duplicated resource before creation") rootCmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings, "Defaults to the line ending native to your platform.") kubeConfigFlags.AddFlags(rootCmd.Flags()) matchVersionKubeConfigFlags.AddFlags(rootCmd.Flags()) cmdutil.AddValidateFlags(rootCmd) o.PrintFlags.AddFlags(rootCmd) return rootCmd } func defaultConfigFlags() *genericclioptions.ConfigFlags { return genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) } 0707010000000A000081A400000000000000000000000166C10ABB00000E71000000000000000000000000000000000000001900000000kubectl-dup-0.3.2/go.modmodule dup go 1.22.0 toolchain go1.22.6 require ( github.com/evanphx/json-patch v5.9.0+incompatible github.com/google/uuid v1.6.0 github.com/spf13/cobra v1.8.1 k8s.io/api v0.31.0 k8s.io/apimachinery v0.31.0 k8s.io/cli-runtime v0.31.0 k8s.io/client-go v0.31.0 k8s.io/klog/v2 v2.130.1 k8s.io/kubectl v0.31.0 ) require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/chai2010/gettext-go v1.0.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/imdario/mergo v0.3.16 // 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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/moby/spdystream v0.5.0 // indirect github.com/moby/term 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/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/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.starlark.net v0.0.0-20240725214946-42030a7cedce // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.6.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/component-base v0.31.0 // indirect k8s.io/kube-openapi v0.0.0-20240812233141-91dab695df6f // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.17.3 // indirect sigs.k8s.io/kustomize/kyaml v0.17.2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) 0707010000000B000081A400000000000000000000000166C10ABB00005104000000000000000000000000000000000000001900000000kubectl-dup-0.3.2/go.sumgithub.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/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.3 h1:9liNh8t+u26xl5ddmWLmsOsdNLwkdRTg5AG+JnTiM80= github.com/chai2010/gettext-go v1.0.3/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= 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.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.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= 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.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/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.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= 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-20240725214946-42030a7cedce h1:YyGqCjZtGZJ+mRPaenEiB87afEO2MFRzLiJNZ0Z0bPw= go.starlark.net v0.0.0-20240725214946-42030a7cedce/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= 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-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 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/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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= k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/cli-runtime v0.31.0 h1:V2Q1gj1u3/WfhD475HBQrIYsoryg/LrhhK4RwpN+DhA= k8s.io/cli-runtime v0.31.0/go.mod h1:vg3H94wsubuvWfSmStDbekvbla5vFGC+zLWqcf+bGDw= k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= 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-20240812233141-91dab695df6f h1:bnWtxXWdAl5bVOCEPoNdvMkyj6cTW3zxHuwKIakuV9w= k8s.io/kube-openapi v0.0.0-20240812233141-91dab695df6f/go.mod h1:G0W3eI9gG219NHRq3h5uQaRBl4pj4ZpwzRP5ti8y770= k8s.io/kubectl v0.31.0 h1:kANwAAPVY02r4U4jARP/C+Q1sssCcN/1p9Nk+7BQKVg= k8s.io/kubectl v0.31.0/go.mod h1:pB47hhFypGsaHAPjlwrNbvhXgmuAr01ZBvAIIUaI8d4= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/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.17.3 h1:6GCuHSsxq7fN5yhF2XrC+AAr8gxQwhexgHflOAD/JJU= sigs.k8s.io/kustomize/api v0.17.3/go.mod h1:TuDH4mdx7jTfK61SQ/j1QZM/QWR+5rmEiNjvYlhzFhc= sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0= sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= 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.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 0707010000000C000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000001700000000kubectl-dup-0.3.2/imgs0707010000000D000081A400000000000000000000000166C10ABB00001742000000000000000000000000000000000000001F00000000kubectl-dup-0.3.2/imgs/dup.svg<?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1665.086px" height="567.029px" viewBox="0 0 1665.086 567.029" enable-background="new 0 0 1665.086 567.029" xml:space="preserve"> <g> <polygon fill="#FFFFFF" points="787.366,94.488 603.874,316.331 881.293,472.541 1054.531,256.159 "/> <g> <g> <path fill="#FED93E" d="M897.023,242.629c9.98,0.062,17.896,3.685,23.761,10.88c5.864,7.196,8.75,17.4,8.674,30.632 c-0.047,6.396-1.026,12.163-2.955,17.299c-1.937,5.133-4.478,9.487-7.656,13.041c-3.165,3.559-6.806,6.301-10.939,8.232 c-4.138,1.915-8.481,2.871-13.041,2.838c-4.543-0.028-8.498-0.875-11.849-2.514c-3.357-1.654-6.75-3.888-10.203-6.731 l0.565,13.494l3.257,136.029l-11.897-9.969l-4.314-211.512l11.06,0.066l1.076,9.276l0.494,0.008 c3.163-3.024,6.785-5.627,10.866-7.818C887.989,243.686,892.367,242.601,897.023,242.629z M894.027,253.831 c-3.682-0.031-7.16,0.847-10.428,2.613c-3.262,1.77-6.53,4.493-9.807,8.152l-0.254,41.305c3.332,3.052,6.547,5.219,9.633,6.488 c3.073,1.258,6.242,1.9,9.494,1.929c3.147,0.022,6.105-0.693,8.873-2.139c2.781-1.442,5.211-3.495,7.276-6.134 c2.089-2.646,3.735-5.812,4.951-9.482c1.211-3.69,1.834-7.788,1.864-12.351c0.063-9.541-1.785-16.983-5.552-22.309 C906.319,256.557,900.972,253.87,894.027,253.831z"/> <path fill="#FED93E" d="M738.673,322.61c-9.972-0.065-17.88-3.69-23.748-10.89c-5.859-7.192-8.744-17.396-8.666-30.628 c0.045-6.391,1.022-12.157,2.957-17.296c1.93-5.136,4.479-9.482,7.643-13.041c3.163-3.554,6.811-6.299,10.948-8.225 c4.129-1.924,8.471-2.868,13.024-2.852c4.549,0.031,8.51,0.881,11.856,2.524c3.344,1.641,6.746,3.886,10.206,6.734l-0.57-13.505 l0.685-107.991l13.192,0.635l-0.925,192.813l-11.057-0.073l-1.081-9.272l-0.487-0.005c-3.161,3.016-6.775,5.621-10.855,7.813 C747.705,321.55,743.339,322.638,738.673,322.61z M741.673,311.408c3.692,0.022,7.161-0.851,10.431-2.616 c3.257-1.768,6.532-4.484,9.801-8.149l0.266-41.305c-3.344-3.053-6.547-5.214-9.628-6.488c-3.087-1.259-6.254-1.903-9.508-1.929 c-3.14-0.017-6.1,0.696-8.873,2.141c-2.773,1.446-5.202,3.492-7.271,6.134c-2.077,2.647-3.727,5.804-4.942,9.475 c-1.219,3.685-1.837,7.797-1.864,12.351c-0.062,9.541,1.786,16.982,5.549,22.313C729.393,308.677,734.736,311.36,741.673,311.408 z"/> <path fill="#FED93E" d="M825.355,242.176c8.447,0.051,14.581,2.688,18.391,7.926c3.822,5.223,5.694,12.927,5.628,23.119 l-0.316,50.083l-13.491-0.084l0.309-48.291c0.041-7.479-1.091-12.882-3.392-16.2c-2.314-3.332-6.078-4.998-11.272-5.037 c-4.126-0.025-7.759,1.009-10.916,3.105c-3.159,2.088-6.65,5.457-10.475,10.095l-0.353,56.099l-13.335-0.078l0.501-79.036 l11.054,0.078l1.067,12.356l0.483,0.003c3.715-4.311,7.615-7.75,11.693-10.33C815.011,243.4,819.817,242.143,825.355,242.176z"/> <polygon fill="#FED93E" points="776.191,129.375 778.003,106.735 603.874,316.331 616.118,322.411 "/> <polygon fill="#FED93E" points="876.363,454.39 877.537,470.674 603.874,316.331 623.133,312.935 "/> </g> </g> <g> <g> <path fill="#5C2D88" d="M768.065,327.242c-9.982-0.062-17.896-3.688-23.763-10.884c-5.862-7.192-8.752-17.396-8.672-30.63 c0.049-6.394,1.026-12.161,2.955-17.297c1.935-5.133,4.479-9.487,7.655-13.041c3.163-3.559,6.804-6.304,10.941-8.232 c4.135-1.918,8.479-2.874,13.038-2.838c4.543,0.028,8.498,0.872,11.851,2.51c3.354,1.655,6.748,3.892,10.201,6.735l-0.565-13.494 l-2.852-140.136l11.492,14.074l4.314,211.513l-11.059-0.067l-1.074-9.275l-0.495-0.008c-3.161,3.024-6.784,5.627-10.869,7.818 C777.098,326.186,772.72,327.267,768.065,327.242z M771.06,316.037c3.682,0.034,7.16-0.844,10.428-2.613 c3.265-1.767,6.529-4.49,9.809-8.149l0.255-41.305c-3.333-3.055-6.547-5.219-9.639-6.49c-3.07-1.256-6.24-1.901-9.49-1.93 c-3.146-0.02-6.106,0.693-8.873,2.142c-2.782,1.442-5.212,3.492-7.277,6.131c-2.089,2.647-3.735,5.812-4.951,9.485 c-1.208,3.688-1.834,7.791-1.865,12.351c-0.062,9.538,1.79,16.982,5.553,22.309C758.771,313.312,764.115,315.998,771.06,316.037z "/> <path fill="#5C2D88" d="M926.414,247.261c9.971,0.062,17.883,3.69,23.751,10.886c5.859,7.193,8.745,17.397,8.663,30.632 c-0.041,6.388-1.022,12.157-2.957,17.296c-1.933,5.133-4.479,9.479-7.644,13.039c-3.164,3.553-6.81,6.301-10.944,8.224 c-4.132,1.927-8.474,2.871-13.027,2.852c-4.548-0.03-8.51-0.878-11.855-2.521c-3.341-1.644-6.746-3.889-10.207-6.737l0.57,13.508 l-0.686,107.989l-13.191-0.634l0.926-192.813l11.056,0.073l1.081,9.272l0.487,0.003c3.162-3.017,6.779-5.622,10.854-7.816 C917.382,248.317,921.748,247.233,926.414,247.261z M923.414,258.463c-3.692-0.025-7.159,0.851-10.43,2.617 c-3.257,1.764-6.533,4.483-9.802,8.146l-0.266,41.308c3.341,3.053,6.55,5.214,9.631,6.488c3.087,1.255,6.251,1.907,9.505,1.929 c3.14,0.015,6.103-0.696,8.873-2.145c2.773-1.444,5.206-3.488,7.273-6.13c2.075-2.647,3.724-5.804,4.943-9.475 c1.216-3.685,1.834-7.8,1.862-12.356c0.061-9.538-1.787-16.977-5.55-22.313C935.695,261.194,930.351,258.511,923.414,258.463z"/> <path fill="#5C2D88" d="M839.735,327.692c-8.452-0.051-14.585-2.685-18.395-7.923c-3.822-5.225-5.695-12.93-5.628-23.119 l0.315-50.083l13.492,0.085l-0.305,48.287c-0.045,7.481,1.087,12.882,3.388,16.203c2.318,3.329,6.078,4.996,11.271,5.035 c4.127,0.024,7.76-1.01,10.917-3.104c3.161-2.091,6.65-5.457,10.478-10.095l0.352-56.098l13.333,0.075l-0.501,79.038 l-11.054-0.078l-1.067-12.359h-0.481c-3.718,4.309-7.617,7.746-11.695,10.327C850.076,326.468,845.27,327.726,839.735,327.692z" /> <polygon fill="#5C2D88" points="888.896,440.493 888.683,463.928 1061.212,253.54 1047.771,246.867 "/> <polygon fill="#5C2D88" points="790.461,112.922 788.327,94.965 1050.626,248.284 1041.954,256.937 "/> </g> </g> </g> </svg> 0707010000000E000081A400000000000000000000000166C10ABB0000008E000000000000000000000000000000000000001B00000000kubectl-dup-0.3.2/justfiledup: go mod download && GOOS=linux GOARCH=amd64 go build -a -ldflags="-s -w" -o ./bin/kubectl-dup . clean: rm -rf bin test: go test ... 0707010000000F000081A400000000000000000000000166C10ABB00000108000000000000000000000000000000000000001A00000000kubectl-dup-0.3.2/main.gopackage main import ( cmd "dup/cmd" "os" "k8s.io/cli-runtime/pkg/genericiooptions" ) func main() { root := cmd.NewRootCmd(genericiooptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}) if err := root.Execute(); err != nil { os.Exit(1) } } 07070100000010000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000001600000000kubectl-dup-0.3.2/pkg07070100000011000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000002000000000kubectl-dup-0.3.2/pkg/duplicate07070100000012000081A400000000000000000000000166C10ABB0000111E000000000000000000000000000000000000002D00000000kubectl-dup-0.3.2/pkg/duplicate/duplicate.gopackage duplicate import ( duputil "dup/pkg/util" "fmt" "strings" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/resource" ) const LOOP_COMMAND = "tail -f /dev/null" type PodOptions struct { DuplicateInnerPod bool DisableProbes bool LoopCommand bool Image string } func Clone(opts *PodOptions, objects []*resource.Info) ([]*runtime.Object, error) { var ret []*runtime.Object for i := range objects { obj := objects[i] objKind := obj.Object.GetObjectKind().GroupVersionKind().Kind if hasPodSpec(objKind) { dResource, err := cloneResourceWithPod(obj.Object, opts) if err != nil { return nil, err } ret = append(ret, dResource) } else { dResource, err := cloneGenericResource(obj.Object) if err != nil { return nil, err } ret = append(ret, dResource) } } return ret, nil } func hasPodSpec(kind string) bool { switch kind { case "Deployment", "CronJob", "StatefulSet", "Job", "Pod": return true } return false } func unstructuredToType(in runtime.Object, out runtime.Object) error { unstructured, ok := in.(*unstructured.Unstructured) if !ok { return fmt.Errorf("Error converting runtime.Object to unstructured") } err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured.Object, out) if err != nil { return fmt.Errorf("Error converting unstructured to Deploy: %v\n", err) } return nil } func cloneResourceWithPod(obj runtime.Object, opts *PodOptions) (*runtime.Object, error) { var dupObject runtime.Object var metadata *metav1.ObjectMeta var spec *corev1.PodSpec objType := obj.GetObjectKind().GroupVersionKind().Kind switch objType { case "StatefulSet": dupObject = &appsv1.StatefulSet{} unstructuredToType(obj, dupObject) metadata, spec = extractPod[StatefulSetAdapter](StatefulSetAdapter{dupObject.(*appsv1.StatefulSet)}) case "Deployment": dupObject = &appsv1.Deployment{} unstructuredToType(obj, dupObject) metadata, spec = extractPod[DeploymentAdapter](DeploymentAdapter{dupObject.(*appsv1.Deployment)}) case "CronJob": dupObject = &batchv1.CronJob{} unstructuredToType(obj, dupObject) metadata, spec = extractPod[CronJobAdapter](CronJobAdapter{dupObject.(*batchv1.CronJob)}) case "Job": dupObject = &batchv1.Job{} unstructuredToType(obj, dupObject) metadata, spec = extractPod[JobAdapter](JobAdapter{dupObject.(*batchv1.Job)}) case "Pod": dupObject = &corev1.Pod{} unstructuredToType(obj, dupObject) metadata, spec = extractPod[PodAdapter](PodAdapter{dupObject.(*corev1.Pod)}) default: return nil, fmt.Errorf("object type %s does not have PodSpec or is not supported", objType) } applyOptions(objType, spec, metadata, opts) err := setSuffixedName(&dupObject) if err != nil { return nil, err } return &dupObject, nil } func setSuffixedName(obj *runtime.Object) error { accessor := meta.NewAccessor() name, err := accessor.Name(*obj) if err != nil { return err } suffixedName := duputil.GenerateResourceName(name) accessor.SetName(*obj, suffixedName) return nil } func cloneGenericResource(obj runtime.Object) (*runtime.Object, error) { objCopy := obj.DeepCopyObject() err := setSuffixedName(&objCopy) if err != nil { return nil, err } return &objCopy, nil } func applyOptions(kind string, spec *corev1.PodSpec, meta *metav1.ObjectMeta, opts *PodOptions) { if opts != nil { if opts.DisableProbes { disableProbes(spec) } if opts.LoopCommand { setCommand(spec) } if kind == "Pod" { removeOwnership(meta) } } } func disableProbes(podSpec *corev1.PodSpec) { containers := podSpec.Containers for i := range containers { containers[i].ReadinessProbe = nil containers[i].LivenessProbe = nil } } func setCommand(podSpec *corev1.PodSpec) { command := strings.Split(LOOP_COMMAND, " ") containers := podSpec.Containers for i := range containers { containers[i].Command = command } } func removeOwnership(metadata *metav1.ObjectMeta) { delete(metadata.Labels, "app.kubernetes.io/instance") delete(metadata.Labels, "app.kubernetes.io/name") metadata.OwnerReferences = nil metadata.UID = "" metadata.ResourceVersion = "" } 07070100000013000081A400000000000000000000000166C10ABB0000069F000000000000000000000000000000000000002E00000000kubectl-dup-0.3.2/pkg/duplicate/podextract.gopackage duplicate import ( appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type MetadataSpecExtractor[T any] interface { GetPodMetadata() *metav1.ObjectMeta GetPodSpec() *corev1.PodSpec } func extractPod[T MetadataSpecExtractor[T]](obj T) (*metav1.ObjectMeta, *corev1.PodSpec) { return obj.GetPodMetadata(), obj.GetPodSpec() } type StatefulSetAdapter struct { *appsv1.StatefulSet } func (s StatefulSetAdapter) GetPodMetadata() *metav1.ObjectMeta { return &s.StatefulSet.Spec.Template.ObjectMeta } func (s StatefulSetAdapter) GetPodSpec() *corev1.PodSpec { return &s.StatefulSet.Spec.Template.Spec } type DeploymentAdapter struct { *appsv1.Deployment } func (s DeploymentAdapter) GetPodMetadata() *metav1.ObjectMeta { return &s.Deployment.Spec.Template.ObjectMeta } func (s DeploymentAdapter) GetPodSpec() *corev1.PodSpec { return &s.Deployment.Spec.Template.Spec } type CronJobAdapter struct { *batchv1.CronJob } func (s CronJobAdapter) GetPodMetadata() *metav1.ObjectMeta { return &s.CronJob.Spec.JobTemplate.Spec.Template.ObjectMeta } func (s CronJobAdapter) GetPodSpec() *corev1.PodSpec { return &s.CronJob.Spec.JobTemplate.Spec.Template.Spec } type JobAdapter struct { *batchv1.Job } func (s JobAdapter) GetPodMetadata() *metav1.ObjectMeta { return &s.Job.Spec.Template.ObjectMeta } func (s JobAdapter) GetPodSpec() *corev1.PodSpec { return &s.Job.Spec.Template.Spec } type PodAdapter struct { *corev1.Pod } func (s PodAdapter) GetPodMetadata() *metav1.ObjectMeta { return &s.Pod.ObjectMeta } func (s PodAdapter) GetPodSpec() *corev1.PodSpec { return &s.Pod.Spec } 07070100000014000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000001D00000000kubectl-dup-0.3.2/pkg/editor07070100000015000081A400000000000000000000000166C10ABB00004909000000000000000000000000000000000000002C00000000kubectl-dup-0.3.2/pkg/editor/editoptions.go/* Copyright 2017 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 editor import ( "bufio" "bytes" "fmt" "io" "os" "path/filepath" goruntime "runtime" "strings" "dup/pkg/duplicate" jsonpatch "github.com/evanphx/json-patch" "github.com/spf13/cobra" "k8s.io/klog/v2" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericiooptions" "k8s.io/cli-runtime/pkg/printers" "k8s.io/cli-runtime/pkg/resource" _ "k8s.io/client-go/plugin/pkg/client/auth" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/cmd/util/editor/crlf" "k8s.io/kubectl/pkg/scheme" "k8s.io/kubectl/pkg/util" ) var SupportedSubresources = []string{"status"} var encoder = scheme.DefaultJSONEncoder() // EditOptions contains all the options for running edit cli command. type EditOptions struct { PrintFlags *genericclioptions.PrintFlags ToPrinter func(string) (printers.ResourcePrinter, error) OutputPatch bool WindowsLineEndings bool SkipEdit bool DuplicateOptions *duplicate.PodOptions cmdutil.ValidateOptions ValidationDirective string OriginalResult *resource.Result CmdNamespace string ApplyAnnotation bool ChangeCause string managedFields map[types.UID][]metav1.ManagedFieldsEntry genericiooptions.IOStreams f cmdutil.Factory editPrinterOptions *editPrinterOptions updatedResultGetter func(data []byte) *resource.Result FieldManager string Subresource string } type DuplicateOptions struct { DuplicatePod bool RemoveProbes bool Image string } // NewEditOptions returns an initialized EditOptions instance func NewEditOptions(ioStreams genericiooptions.IOStreams) *EditOptions { return &EditOptions{ PrintFlags: genericclioptions.NewPrintFlags("edited").WithTypeSetter(scheme.Scheme), editPrinterOptions: &editPrinterOptions{ // create new editor-specific PrintFlags, with all // output flags disabled, except json / yaml printFlags: (&genericclioptions.PrintFlags{ JSONYamlPrintFlags: genericclioptions.NewJSONYamlPrintFlags(), }).WithDefaultOutput("yaml"), ext: ".yaml", addHeader: true, }, WindowsLineEndings: goruntime.GOOS == "windows", IOStreams: ioStreams, DuplicateOptions: &duplicate.PodOptions{}, } } type editPrinterOptions struct { printFlags *genericclioptions.PrintFlags ext string addHeader bool } func (e *editPrinterOptions) Complete(fromPrintFlags *genericclioptions.PrintFlags) error { if e.printFlags == nil { return fmt.Errorf("missing PrintFlags in editor printer options") } // bind output format from existing printflags if fromPrintFlags != nil && len(*fromPrintFlags.OutputFormat) > 0 { e.printFlags.OutputFormat = fromPrintFlags.OutputFormat } // prevent a commented header at the top of the user's // default editor if presenting contents as json. if *e.printFlags.OutputFormat == "json" { e.addHeader = false e.ext = ".json" return nil } // we default to yaml if check above is false, as only json or yaml are supported e.addHeader = true e.ext = ".yaml" return nil } func (e *editPrinterOptions) PrintObj(obj runtime.Object, out io.Writer) error { p, err := e.printFlags.ToPrinter() if err != nil { return err } return p.PrintObj(obj, out) } // Complete completes all the required options func (o *EditOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error { var err error o.f = f o.editPrinterOptions.Complete(o.PrintFlags) o.CmdNamespace, _, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { return err } o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) if err != nil { return err } b := f.NewBuilder(). Unstructured(). ResourceTypeOrNameArgs(true, args...). NamespaceParam(o.CmdNamespace).DefaultNamespace(). ContinueOnError(). Flatten(). Do() err = b.Err() if err != nil { return err } objects, err := b.Infos() if err != nil { return err } resources, err := duplicate.Clone(o.DuplicateOptions, objects) if err != nil { return err } resourceObjects, err := objsBody(resources) if err != nil { return err } result, err := o.Build(resourceObjects, o.ValidationDirective) if err != nil { return err } o.OriginalResult = result o.updatedResultGetter = func(data []byte) *resource.Result { // resource builder to read objects from edited data return f.NewBuilder(). Unstructured(). Stream(bytes.NewReader(data), "edited-file"). ContinueOnError(). Flatten(). Do() } o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { o.PrintFlags.NamePrintFlags.Operation = operation return o.PrintFlags.ToPrinter() } return nil } func (o *EditOptions) createResources(obj []*resource.Info) error { visitor := resource.InfoListVisitor(obj) if err := o.restoreManagedFields(obj); err != nil { return err } // need to make sure the original namespace wasn't changed while editing if err := visitor.Visit(resource.RequireNamespace(o.CmdNamespace)); err != nil { return err } // iterate through all items to apply annotations if err := o.visitAnnotation(visitor); err != nil { return err } err := o.visitToCreate(visitor) if err != nil { return err } return nil } // Run performs the execution func (o *EditOptions) Run() error { // CreateDuplicatePod(context.Background(), ioStreams, clientset, deployment, namespace, podName, edit) edit := NewDefaultEditor(editorEnvs()) // editFn is invoked for each edit session (once with a list for normal edit, once for each individual resource in a edit-on-create invocation) editFn := func(obj []*resource.Info) error { var ( results = editResults{} edited = []byte{} file string err error ) containsError := false // loop until we succeed or cancel editing for { // get the object we're going to serialize as input to the editor originalObj := obj[0].Object // generate the file to edit buf := &bytes.Buffer{} var w io.Writer = buf if o.WindowsLineEndings { w = crlf.NewCRLFWriter(w) } if o.editPrinterOptions.addHeader { results.header.writeTo(w) } if !containsError { if err := o.extractManagedFields(originalObj); err != nil { return preservedFile(err, results.file, o.ErrOut) } if err := o.editPrinterOptions.PrintObj(originalObj, w); err != nil { return preservedFile(err, results.file, o.ErrOut) } } else { // In case of an error, preserve the edited file. // Remove the comments (header) from it since we already // have included the latest header in the buffer above. buf.Write(cmdutil.ManualStrip(edited)) } // launch the editor editedDiff := edited edited, file, err = edit.LaunchTempFile(fmt.Sprintf("%s-edit-", filepath.Base(os.Args[0])), o.editPrinterOptions.ext, buf) if err != nil { return preservedFile(err, results.file, o.ErrOut) } // If we're retrying the loop because of an error, and no change was made in the file, short-circuit if containsError && bytes.Equal(cmdutil.StripComments(editedDiff), cmdutil.StripComments(edited)) { return preservedFile(fmt.Errorf("%s", "Edit cancelled, no valid changes were saved."), file, o.ErrOut) } // cleanup any file from the previous pass if len(results.file) > 0 { os.Remove(results.file) } klog.V(4).Infof("User edited:\n%s", string(edited)) // Apply validation schema, err := o.f.Validator(o.ValidationDirective) if err != nil { return preservedFile(err, file, o.ErrOut) } err = schema.ValidateBytes(cmdutil.StripComments(edited)) if err != nil { results = editResults{ file: file, } containsError = true fmt.Fprintln(o.ErrOut, results.addError(apierrors.NewInvalid(corev1.SchemeGroupVersion.WithKind("").GroupKind(), "", field.ErrorList{field.Invalid(nil, "The edited file failed validation", fmt.Sprintf("%v", err))}), obj[0])) continue } lines, err := hasLines(bytes.NewBuffer(edited)) if err != nil { return preservedFile(err, file, o.ErrOut) } if !lines { os.Remove(file) fmt.Fprintln(o.ErrOut, "Edit cancelled, saved file was empty.") return nil } results = editResults{ file: file, } // parse the edited file updatedInfos, err := o.updatedResultGetter(edited).Infos() if err != nil { // syntax error containsError = true results.header.reasons = append(results.header.reasons, editReason{head: fmt.Sprintf("The edited file had a syntax error: %v", err)}) continue } containsError = false // restore managed fields to original object if err := o.restoreManagedFields(obj); err != nil { return preservedFile(err, file, o.ErrOut) } err = o.createResources(updatedInfos) if err != nil { return preservedFile(err, results.file, o.ErrOut) } if len(results.edit) == 0 { if results.notfound == 0 { os.Remove(file) } else { fmt.Fprintf(o.Out, "The edits you made on deleted resources have been saved to %q\n", file) } return nil } if len(results.header.reasons) > 0 { containsError = true } } } return o.OriginalResult.Visit(func(info *resource.Info, err error) error { objects := []*resource.Info{info} if o.SkipEdit { err := o.createResources(objects) if err != nil { return err } return nil } return editFn(objects) }) } func (o *EditOptions) Build(reader io.Reader, validate string) (*resource.Result, error) { schema, err := o.f.Validator(validate) if err != nil { return nil, err } result := o.f.NewBuilder(). Unstructured(). Schema(schema). Stream(reader, ""). Do() err = result.Err() if err != nil { return nil, err } return result, nil } func objBody(obj runtime.Object) (io.ReadCloser, error) { encoded, err := runtime.Encode(encoder, obj) if err != nil { return nil, err } return io.NopCloser(bytes.NewReader([]byte(encoded))), nil } func objsBody(objs []*runtime.Object) (io.Reader, error) { var readers []io.Reader for _, obj := range objs { encoded, err := runtime.Encode(encoder, *obj) if err != nil { return nil, err } reader := bytes.NewReader([]byte(encoded)) readers = append(readers, reader) } return io.MultiReader(readers...), nil } func (o *EditOptions) extractManagedFields(obj runtime.Object) error { o.managedFields = make(map[types.UID][]metav1.ManagedFieldsEntry) if meta.IsListType(obj) { err := meta.EachListItem(obj, func(obj runtime.Object) error { uid, mf, err := clearManagedFields(obj) if err != nil { return err } o.managedFields[uid] = mf return nil }) return err } uid, mf, err := clearManagedFields(obj) if err != nil { return err } o.managedFields[uid] = mf return nil } func clearManagedFields(obj runtime.Object) (types.UID, []metav1.ManagedFieldsEntry, error) { metaObjs, err := meta.Accessor(obj) if err != nil { return "", nil, err } mf := metaObjs.GetManagedFields() metaObjs.SetManagedFields(nil) return metaObjs.GetUID(), mf, nil } func (o *EditOptions) restoreManagedFields(infos []*resource.Info) error { for _, info := range infos { metaObjs, err := meta.Accessor(info.Object) if err != nil { return err } mf := o.managedFields[metaObjs.GetUID()] metaObjs.SetManagedFields(mf) } return nil } func (o *EditOptions) annotationPatch(update *resource.Info) error { patch, _, patchType, err := GetApplyPatch(update.Object.(runtime.Unstructured)) if err != nil { return err } mapping := update.ResourceMapping() client, err := o.f.UnstructuredClientForMapping(mapping) if err != nil { return err } helper := resource.NewHelper(client, mapping). WithFieldManager(o.FieldManager). WithFieldValidation(o.ValidationDirective). WithSubresource(o.Subresource) _, err = helper.Patch(o.CmdNamespace, update.Name, patchType, patch, nil) return err } // GetApplyPatch is used to get and apply patches func GetApplyPatch(obj runtime.Unstructured) ([]byte, []byte, types.PatchType, error) { beforeJSON, err := encodeToJSON(obj) if err != nil { return nil, []byte(""), types.MergePatchType, err } objCopy := obj.DeepCopyObject() accessor := meta.NewAccessor() annotations, err := accessor.Annotations(objCopy) if err != nil { return nil, beforeJSON, types.MergePatchType, err } if annotations == nil { annotations = map[string]string{} } annotations[corev1.LastAppliedConfigAnnotation] = string(beforeJSON) accessor.SetAnnotations(objCopy, annotations) afterJSON, err := encodeToJSON(objCopy.(runtime.Unstructured)) if err != nil { return nil, beforeJSON, types.MergePatchType, err } patch, err := jsonpatch.CreateMergePatch(beforeJSON, afterJSON) return patch, beforeJSON, types.MergePatchType, err } func encodeToJSON(obj runtime.Unstructured) ([]byte, error) { serialization, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) if err != nil { return nil, err } js, err := yaml.ToJSON(serialization) if err != nil { return nil, err } return js, nil } func (o *EditOptions) visitToCreate(createVisitor resource.Visitor) error { err := createVisitor.Visit(func(info *resource.Info, incomingErr error) error { obj, err := resource.NewHelper(info.Client, info.Mapping). WithFieldManager(o.FieldManager). WithFieldValidation(o.ValidationDirective). Create(info.Namespace, true, info.Object) if err != nil { return err } info.Refresh(obj, true) printer, err := o.ToPrinter("created") if err != nil { return err } return printer.PrintObj(info.Object, o.Out) }) return err } func (o *EditOptions) visitAnnotation(annotationVisitor resource.Visitor) error { // iterate through all items to apply annotations err := annotationVisitor.Visit(func(info *resource.Info, incomingErr error) error { // put configuration annotation in "updates" if o.ApplyAnnotation { if err := util.CreateOrUpdateAnnotation(true, info.Object, scheme.DefaultJSONEncoder()); err != nil { return err } } return nil }) return err } // editReason preserves a message about the reason this file must be edited again type editReason struct { head string other []string } // editHeader includes a list of reasons the edit must be retried type editHeader struct { reasons []editReason } // writeTo outputs the current header information into a stream func (h *editHeader) writeTo(w io.Writer) error { fmt.Fprint(w, `# Please edit the object below. Lines beginning with a '#' will be ignored, # and an empty file will abort the edit. If an error occurs while saving this file will be # reopened with the relevant failures. # `) for _, r := range h.reasons { if len(r.other) > 0 { fmt.Fprintf(w, "# %s:\n", hashOnLineBreak(r.head)) } else { fmt.Fprintf(w, "# %s\n", hashOnLineBreak(r.head)) } for _, o := range r.other { fmt.Fprintf(w, "# * %s\n", hashOnLineBreak(o)) } fmt.Fprintln(w, "#") } return nil } // editResults capture the result of an update type editResults struct { header editHeader retryable int notfound int edit []*resource.Info file string } func (r *editResults) addError(err error, info *resource.Info) string { resourceString := info.Mapping.Resource.Resource if len(info.Mapping.Resource.Group) > 0 { resourceString = resourceString + "." + info.Mapping.Resource.Group } switch { case apierrors.IsInvalid(err): r.edit = append(r.edit, info) reason := editReason{ head: fmt.Sprintf("%s %q was not valid", resourceString, info.Name), } if err, ok := err.(apierrors.APIStatus); ok { if details := err.Status().Details; details != nil { for _, cause := range details.Causes { reason.other = append(reason.other, fmt.Sprintf("%s: %s", cause.Field, cause.Message)) } } } r.header.reasons = append(r.header.reasons, reason) return fmt.Sprintf("error: %s %q is invalid", resourceString, info.Name) case apierrors.IsNotFound(err): r.notfound++ return fmt.Sprintf("error: %s %q could not be found on the server", resourceString, info.Name) default: r.retryable++ return fmt.Sprintf("error: %s %q could not be patched: %v", resourceString, info.Name, err) } } // preservedFile writes out a message about the provided file if it exists to the // provided output stream when an error happens. Used to notify the user where // their updates were preserved. func preservedFile(err error, path string, out io.Writer) error { if len(path) > 0 { if _, err := os.Stat(path); !os.IsNotExist(err) { fmt.Fprintf(out, "A copy of your changes has been stored to %q\n", path) } } return err } // hasLines returns true if any line in the provided stream is non empty - has non-whitespace // characters, or the first non-whitespace character is a '#' indicating a comment. Returns // any errors encountered reading the stream. func hasLines(r io.Reader) (bool, error) { // TODO: if any files we read have > 64KB lines, we'll need to switch to bytes.ReadLine // TODO: probably going to be secrets s := bufio.NewScanner(r) for s.Scan() { if line := strings.TrimSpace(s.Text()); len(line) > 0 && line[0] != '#' { return true, nil } } if err := s.Err(); err != nil && err != io.EOF { return false, err } return false, nil } // hashOnLineBreak returns a string built from the provided string by inserting any necessary '#' // characters after '\n' characters, indicating a comment. func hashOnLineBreak(s string) string { r := "" for i, ch := range s { j := i + 1 if j < len(s) && ch == '\n' && s[j] != '#' { r += "\n# " } else { r += string(ch) } } return r } // editorEnvs returns an ordered list of env vars to check for editor preferences. func editorEnvs() []string { return []string{ "KUBE_EDITOR", "EDITOR", } } 07070100000016000081A400000000000000000000000166C10ABB000011CC000000000000000000000000000000000000002700000000kubectl-dup-0.3.2/pkg/editor/editor.go/* Copyright 2015 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 editor import ( "fmt" "io" "os" "os/exec" "path/filepath" "runtime" "strings" "k8s.io/klog/v2" "k8s.io/kubectl/pkg/util/term" ) const ( // sorry, blame Git // TODO: on Windows rely on 'start' to launch the editor associated // with the given file type. If we can't because of the need of // blocking, use a script with 'ftype' and 'assoc' to detect it. defaultEditor = "vi" defaultShell = "/bin/bash" windowsEditor = "notepad" windowsShell = "cmd" ) // Editor holds the command-line args to fire up the editor type Editor struct { Args []string Shell bool } // NewDefaultEditor creates a struct Editor that uses the OS environment to // locate the editor program, looking at EDITOR environment variable to find // the proper command line. If the provided editor has no spaces, or no quotes, // it is treated as a bare command to be loaded. Otherwise, the string will // be passed to the user's shell for execution. func NewDefaultEditor(envs []string) Editor { args, shell := defaultEnvEditor(envs) return Editor{ Args: args, Shell: shell, } } func defaultEnvShell() []string { shell := os.Getenv("SHELL") if len(shell) == 0 { shell = platformize(defaultShell, windowsShell) } flag := "-c" if shell == windowsShell { flag = "/C" } return []string{shell, flag} } func defaultEnvEditor(envs []string) ([]string, bool) { var editor string for _, env := range envs { if len(env) > 0 { editor = os.Getenv(env) } if len(editor) > 0 { break } } if len(editor) == 0 { editor = platformize(defaultEditor, windowsEditor) } if !strings.Contains(editor, " ") { return []string{editor}, false } if !strings.ContainsAny(editor, "\"'\\") { return strings.Split(editor, " "), false } // rather than parse the shell arguments ourselves, punt to the shell shell := defaultEnvShell() return append(shell, editor), true } func (e Editor) args(path string) []string { args := make([]string, len(e.Args)) copy(args, e.Args) if e.Shell { last := args[len(args)-1] args[len(args)-1] = fmt.Sprintf("%s %q", last, path) } else { args = append(args, path) } return args } // Launch opens the described or returns an error. The TTY will be protected, and // SIGQUIT, SIGTERM, and SIGINT will all be trapped. func (e Editor) Launch(path string) error { if len(e.Args) == 0 { return fmt.Errorf("no editor defined, can't open %s", path) } abs, err := filepath.Abs(path) if err != nil { return err } args := e.args(abs) cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin klog.V(5).Infof("Opening file with editor %v", args) if err := (term.TTY{In: os.Stdin, TryDev: true}).Safe(cmd.Run); err != nil { if err, ok := err.(*exec.Error); ok { if err.Err == exec.ErrNotFound { return fmt.Errorf("unable to launch the editor %q", strings.Join(e.Args, " ")) } } return fmt.Errorf("there was a problem with the editor %q", strings.Join(e.Args, " ")) } return nil } // LaunchTempFile reads the provided stream into a temporary file in the given directory // and file prefix, and then invokes Launch with the path of that file. It will return // the contents of the file after launch, any errors that occur, and the path of the // temporary file so the caller can clean it up as needed. func (e Editor) LaunchTempFile(prefix, suffix string, r io.Reader) ([]byte, string, error) { f, err := os.CreateTemp("", prefix+"*"+suffix) if err != nil { return nil, "", err } defer f.Close() path := f.Name() if _, err := io.Copy(f, r); err != nil { os.Remove(path) return nil, path, err } // This file descriptor needs to close so the next process (Launch) can claim it. f.Close() if err := e.Launch(path); err != nil { return nil, path, err } bytes, err := os.ReadFile(path) return bytes, path, err } func platformize(linux, windows string) string { if runtime.GOOS == "windows" { return windows } return linux } 07070100000017000081A400000000000000000000000166C10ABB0000192E000000000000000000000000000000000000002800000000kubectl-dup-0.3.2/pkg/editor/factory.gopackage editor import ( "errors" "sync" 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/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" openapiclient "k8s.io/client-go/openapi" "k8s.io/client-go/openapi/cached" "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/scheme" "k8s.io/kubectl/pkg/util/openapi" "k8s.io/kubectl/pkg/validation" ) func NewFactory(clientGetter genericclioptions.RESTClientGetter) cmdutil.Factory { if clientGetter == nil { panic("attempt to instantiate client_access_factory with nil clientGetter") } f := &factoryImpl{ clientGetter: clientGetter, } return f } func (f *factoryImpl) KubernetesClientSet() (*kubernetes.Clientset, error) { clientConfig, err := f.ToRESTConfig() if err != nil { return nil, err } return kubernetes.NewForConfig(clientConfig) } func setKubernetesDefaults(config *rest.Config) error { // TODO remove this hack. This is allowing the GetOptions to be serialized. config.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"} if config.APIPath == "" { config.APIPath = "/api" } if config.NegotiatedSerializer == nil { // This codec factory ensures the resources are not converted. Therefore, resources // will not be round-tripped through internal versions. Defaulting does not happen // on the client. config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() } return rest.SetKubernetesDefaults(config) } func (f *factoryImpl) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) { cfg, err := f.clientGetter.ToRESTConfig() if err != nil { return nil, err } if err := setKubernetesDefaults(cfg); err != nil { return nil, err } gvk := mapping.GroupVersionKind switch gvk.Group { case corev1.GroupName: cfg.APIPath = "/api" default: cfg.APIPath = "/apis" } gv := gvk.GroupVersion() cfg.GroupVersion = &gv return restclient.RESTClientFor(cfg) } type factoryImpl struct { clientGetter genericclioptions.RESTClientGetter // Caches OpenAPI document and parsed resources openAPIParser *openapi.CachedOpenAPIParser oapi *openapi.CachedOpenAPIGetter parser sync.Once getter sync.Once } func (f *factoryImpl) Validator(validationDirective string) (validation.Schema, error) { // client-side schema validation is only performed // when the validationDirective is strict. // If the directive is warn, we rely on the ParamVerifyingSchema // to ignore the client-side validation and provide a warning // to the user that attempting warn validation when SS validation // is unsupported is inert. if validationDirective == metav1.FieldValidationIgnore { return validation.NullSchema{}, nil } schema := validation.ConjunctiveSchema{ validation.NewSchemaValidation(f), validation.NoDoubleKeySchema{}, } dynamicClient, err := f.DynamicClient() if err != nil { return nil, err } // Create the FieldValidationVerifier for use in the ParamVerifyingSchema. discoveryClient, err := f.ToDiscoveryClient() if err != nil { return nil, err } // Memory-cache the OpenAPI V3 responses. The disk cache behavior is determined by // the discovery client. oapiV3Client := cached.NewClient(discoveryClient.OpenAPIV3()) queryParam := resource.QueryParamFieldValidation primary := resource.NewQueryParamVerifierV3(dynamicClient, oapiV3Client, queryParam) secondary := resource.NewQueryParamVerifier(dynamicClient, f.openAPIGetter(), queryParam) fallback := resource.NewFallbackQueryParamVerifier(primary, secondary) return validation.NewParamVerifyingSchema(schema, fallback, string(validationDirective)), nil } func (f *factoryImpl) openAPIGetter() discovery.OpenAPISchemaInterface { discovery, err := f.clientGetter.ToDiscoveryClient() if err != nil { return nil } f.getter.Do(func() { f.oapi = openapi.NewOpenAPIGetter(discovery) }) return f.oapi } func (f *factoryImpl) OpenAPISchema() (openapi.Resources, error) { openAPIGetter := f.openAPIGetter() if openAPIGetter == nil { return nil, errors.New("no openapi getter") } // Lazily initialize the OpenAPIParser once f.parser.Do(func() { // Create the caching OpenAPIParser f.openAPIParser = openapi.NewOpenAPIParser(f.openAPIGetter()) }) // Delegate to the OpenAPIPArser return f.openAPIParser.Parse() } func (f *factoryImpl) ToRESTConfig() (*restclient.Config, error) { return f.clientGetter.ToRESTConfig() } func (f *factoryImpl) DynamicClient() (dynamic.Interface, error) { clientConfig, err := f.ToRESTConfig() if err != nil { return nil, err } return dynamic.NewForConfig(clientConfig) } func (f *factoryImpl) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { return f.clientGetter.ToDiscoveryClient() } func (f *factoryImpl) NewBuilder() *resource.Builder { // NewBuilder returns a new resource builder for structured api objects. return resource.NewBuilder(f.clientGetter) } func (f *factoryImpl) OpenAPIV3Client() (openapiclient.Client, error) { discovery, err := f.clientGetter.ToDiscoveryClient() if err != nil { return nil, err } return cached.NewClient(discovery.OpenAPIV3()), nil } func (f *factoryImpl) RESTClient() (*restclient.RESTClient, error) { clientConfig, err := f.ToRESTConfig() if err != nil { return nil, err } setKubernetesDefaults(clientConfig) return restclient.RESTClientFor(clientConfig) } func (f *factoryImpl) ToRESTMapper() (meta.RESTMapper, error) { return f.clientGetter.ToRESTMapper() } func (f *factoryImpl) ToRawKubeConfigLoader() clientcmd.ClientConfig { return f.clientGetter.ToRawKubeConfigLoader() } func (f *factoryImpl) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) { cfg, err := f.clientGetter.ToRESTConfig() if err != nil { return nil, err } if err := restclient.SetKubernetesDefaults(cfg); err != nil { return nil, err } cfg.APIPath = "/apis" if mapping.GroupVersionKind.Group == corev1.GroupName { cfg.APIPath = "/api" } gv := mapping.GroupVersionKind.GroupVersion() cfg.ContentConfig = resource.UnstructuredPlusDefaultContentConfig() cfg.GroupVersion = &gv return restclient.RESTClientFor(cfg) } 07070100000018000041ED00000000000000000000000266C10ABB00000000000000000000000000000000000000000000001B00000000kubectl-dup-0.3.2/pkg/util07070100000019000081A400000000000000000000000166C10ABB000005E2000000000000000000000000000000000000002300000000kubectl-dup-0.3.2/pkg/util/util.gopackage util import ( "fmt" "os" "regexp" "github.com/google/uuid" "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) func GetDefaultNamespace(kubeconfig string) string { defaultNamespace, _, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{}}).Namespace() if err != nil { fmt.Printf("Failed getting current namespace %v\n", err) os.Exit(1) } return defaultNamespace } func GetDefaultKubeconfigPath() string { homeDir, err := os.UserHomeDir() if err != nil { fmt.Println("Could not get home directory:%w", err) } kubeconfigDefaultPath := homeDir + "/.kube/config" return kubeconfigDefaultPath } func GenerateResourceName(input string) string { var result string var suffix = "-dup-" + uuid.New().String()[:4] var maxPodNameLength = 63 - len(suffix) //RFC1035 if len(input) > (maxPodNameLength) { result = input[:maxPodNameLength] + suffix } else { result = input + suffix } return result } func IsValidPod(podName string) bool { // Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names return isValidDNSLabel(podName) } func isValidDNSLabel(input string) bool { // Regular expression for DNS label validation as per RFC 1123 dnsLabelRegex := regexp.MustCompile(`^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$`) return dnsLabelRegex.MatchString(input) } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!159 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor