├── using-client-go-toc-and-some-random-pages.pdf ├── using-codegen ├── pkg │ ├── apis │ │ └── expression │ │ │ └── v1alpha1 │ │ │ ├── doc.go │ │ │ ├── register.go │ │ │ ├── types.go │ │ │ └── zz_generated.deepcopy.go │ └── generated │ │ └── clientset │ │ └── versioned │ │ ├── doc.go │ │ ├── fake │ │ ├── doc.go │ │ ├── register.go │ │ └── clientset_generated.go │ │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ │ ├── typed │ │ └── expression │ │ │ └── v1alpha1 │ │ │ ├── fake │ │ │ ├── doc.go │ │ │ ├── fake_expression_client.go │ │ │ └── fake_expression.go │ │ │ ├── generated_expansion.go │ │ │ ├── doc.go │ │ │ ├── expression_client.go │ │ │ └── expression.go │ │ └── clientset.go ├── manifests │ ├── examples │ │ ├── demo1.yaml │ │ ├── demo2.yaml │ │ ├── demo3.yaml │ │ └── demo4.yaml │ └── crds │ │ └── expression-crd.yaml ├── Makefile ├── hack │ ├── boilerplate.go.txt │ ├── hack.go │ └── hack.sh └── main.go ├── using-dynamic-interface ├── get-and-update-crds │ ├── margherita.yaml │ ├── main.go │ └── pizza_crd.yaml └── list-pods │ └── main.go ├── creating-a-rest-config-instance ├── using-default-rules │ └── main.go └── using-flags │ └── main.go ├── .gitignore ├── Makefile ├── LICENSE ├── labels-and-selectors ├── creating-a-selector │ └── main.go └── list-with-label-selector │ └── main.go ├── README.md ├── using-kubernetes-clientset ├── deleting-a-deployment │ └── main.go ├── listing-pods │ └── main.go ├── updating-a-deployment-image │ └── main.go └── creating-a-deployment │ └── main.go ├── using-rest-client ├── deleting-a-deployment │ └── main.go ├── listing-pods │ └── main.go ├── updating-a-deployment-image │ └── main.go └── creating-a-deployment │ └── main.go ├── using-discovery-client └── main.go ├── watching ├── with-clientset │ └── main.go ├── with-dynamic-interface │ └── main.go └── with-rest-client │ └── main.go ├── using-informers └── main.go ├── go.mod ├── using-retrywatcher └── main.go ├── display-http-calls └── main.go ├── workqueue └── main.go └── go.sum /using-client-go-toc-and-some-random-pages.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucasepe/using-client-go/HEAD/using-client-go-toc-and-some-random-pages.pdf -------------------------------------------------------------------------------- /using-codegen/pkg/apis/expression/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package,register 2 | // +k8s:defaulter-gen=TypeMeta 3 | // +k8s:openapi-gen=true 4 | 5 | // +groupName=example.org 6 | package v1alpha1 7 | -------------------------------------------------------------------------------- /using-codegen/manifests/examples/demo1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: example.org/v1alpha1 2 | kind: Expression 3 | metadata: 4 | name: demo1 5 | namespace: default 6 | spec: 7 | body: x + y + z 8 | data: |- 9 | { 10 | "x": 8, 11 | "y": 1, 12 | "z": 7 13 | } -------------------------------------------------------------------------------- /using-codegen/manifests/examples/demo2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: example.org/v1alpha1 2 | kind: Expression 3 | metadata: 4 | name: demo2 5 | namespace: default 6 | spec: 7 | body: x + y < z 8 | data: |- 9 | { 10 | "x": 8, 11 | "y": 1, 12 | "z": 7 13 | } -------------------------------------------------------------------------------- /using-codegen/manifests/examples/demo3.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: example.org/v1alpha1 2 | kind: Expression 3 | metadata: 4 | name: demo3 5 | namespace: default 6 | spec: 7 | body: x - y * z 8 | data: |- 9 | { 10 | "x": 8, 11 | "y": 1, 12 | "z": 7 13 | } -------------------------------------------------------------------------------- /using-codegen/manifests/examples/demo4.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: example.org/v1alpha1 2 | kind: Expression 3 | metadata: 4 | name: demo4 5 | namespace: default 6 | spec: 7 | body: 0.5 *(x / (y + z)) 8 | data: |- 9 | { 10 | "x": 8, 11 | "y": 1, 12 | "z": 7 13 | } -------------------------------------------------------------------------------- /using-dynamic-interface/get-and-update-crds/margherita.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bella.napoli.it/v1alpha1 2 | kind: Pizza 3 | metadata: 4 | name: margherita 5 | spec: 6 | toppings: 7 | - San Marzano Tomatoes 8 | - Fresh Mozzarella 9 | - Fresh Basil 10 | - Olive Oil 11 | status: 12 | cost: 5.00 13 | -------------------------------------------------------------------------------- /creating-a-rest-config-instance/using-default-rules/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "k8s.io/client-go/tools/clientcmd" 7 | ) 8 | 9 | func main() { 10 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 11 | clientcmd.NewDefaultClientConfigLoadingRules(), 12 | &clientcmd.ConfigOverrides{}, 13 | ) 14 | 15 | namespace, _, err := configLoader.Namespace() 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | cfg, err := configLoader.ClientConfig() 21 | if err != nil { 22 | panic(err) 23 | } 24 | 25 | fmt.Printf("Kubernetes Host: %s (current context namespace: %s)\n", cfg.Host, namespace) 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Intellij 2 | .idea/**/workspace.xml 3 | .idea/**/tasks.xml 4 | .idea/**/encodings.xml 5 | .idea/**/compiler.xml 6 | .idea/**/misc.xml 7 | .idea/**/modules.xml 8 | .idea/**/vcs.xml 9 | 10 | ## VSCode 11 | .vscode/ 12 | 13 | ## File-based project format: 14 | *.iws 15 | *.iml 16 | .idea/ 17 | 18 | # Binaries for programs and plugins 19 | *.exe 20 | *.exe~ 21 | *.dll 22 | *.so 23 | *.dylib 24 | *.dat 25 | *.DS_Store 26 | **/bin/** 27 | 28 | # Test binary, built with `go test -c` 29 | *.test 30 | 31 | # Output of the go coverage tool, specifically when used with LiteIDE 32 | *.out 33 | 34 | # Goreleaser builds 35 | **/dist/** 36 | 37 | # This is my wip ideas folder 38 | experiments/** 39 | 40 | # Dotenv files 41 | .env 42 | **/*.env 43 | 44 | # Vendor dirs 45 | vendor/** 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Set the shell to bash always 2 | SHELL := /bin/bash 3 | 4 | # Variables 5 | KIND_CLUSTER_NAME ?= local-dev 6 | 7 | # Tools 8 | KIND=$(shell which kind) 9 | 10 | # Sets the default goal to be used if no targets were specified on the command line 11 | .DEFAULT_GOAL := help 12 | 13 | ## help: Print this help 14 | .PHONY: help 15 | help: Makefile 16 | @echo 17 | @echo " Choose a command:" 18 | @echo 19 | @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' 20 | @echo 21 | 22 | ## kind.up: Starts the KinD cluster 23 | .PHONY: kind.up 24 | kind.up: 25 | @$(KIND) get kubeconfig --name $(KIND_CLUSTER_NAME) > /dev/null 2>&1 \ 26 | || $(KIND) create cluster --name=$(KIND_CLUSTER_NAME) 27 | 28 | ## kind.down: Shuts down the KinD cluster 29 | .PHONY: kind.down 30 | kind.down: 31 | @$(KIND) delete cluster --name=$(KIND_CLUSTER_NAME) 32 | -------------------------------------------------------------------------------- /using-codegen/Makefile: -------------------------------------------------------------------------------- 1 | # Set the shell to bash always 2 | SHELL := /bin/bash 3 | 4 | UNAME := $(uname -s) 5 | 6 | .PHONY: help 7 | help: ### Show targets documentation 8 | ifeq ($(UNAME), Linux) 9 | @grep -P '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \ 10 | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 11 | else 12 | @awk -F ':.*###' '$$0 ~ FS {printf "%15s%s\n", $$1 ":", $$2}' \ 13 | $(MAKEFILE_LIST) | grep -v '@awk' | sort 14 | endif 15 | 16 | .PHONY: vendor 17 | vendor: ### Vendor dependencies 18 | @go mod vendor 19 | 20 | .PHONY: deps 21 | deps: ### Optimize dependencies 22 | @go mod tidy 23 | 24 | .PHONY: generate 25 | generate: vendor ### Generate code 26 | @bash ./hack/hack.sh 27 | 28 | 29 | .PHONY: install 30 | install: ## Install CRDs 31 | @kubectl apply -f manifests/crds 32 | 33 | .PHONY: clean 34 | clean: ### Clean build files 35 | @go clean 36 | 37 | -------------------------------------------------------------------------------- /creating-a-rest-config-instance/using-flags/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "k8s.io/client-go/tools/clientcmd" 9 | ) 10 | 11 | func main() { 12 | // retrieve the value of the KUBECONFIG environment variable 13 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 14 | // if KUBECONFIG is empty 15 | if len(defaultKubeconfig) == 0 { 16 | // look for file $HOME/.kube/config 17 | defaultKubeconfig = clientcmd.RecommendedHomeFile 18 | } 19 | 20 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 21 | defaultKubeconfig, "absolute path to the kubeconfig file") 22 | 23 | flag.Parse() 24 | 25 | // build the config from the specified kubeconfig filepath 26 | cfg, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | // Just print some `config` struct variables 32 | fmt.Printf("Kubernetes Host: %v\n", cfg.Host) 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Luca Sepe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /using-codegen/hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) YEAR 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ -------------------------------------------------------------------------------- /labels-and-selectors/creating-a-selector/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "k8s.io/apimachinery/pkg/labels" 7 | "k8s.io/apimachinery/pkg/selection" 8 | ) 9 | 10 | const ( 11 | keySupportBy = "app.kubernetes.io/support-by" 12 | keyPartOf = "app.kubernetes.io/part-of" 13 | ) 14 | 15 | func main() { 16 | // requirements contains values, key, and an operator that relates the key and values 17 | supportExists, err := labels.NewRequirement(keySupportBy, selection.Exists, []string{}) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | supportTeam, err := labels.NewRequirement(keySupportBy, selection.In, []string{"team_1", "team_2"}) 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | partOfReq, err := labels.NewRequirement(keyPartOf, selection.Equals, []string{"payment-system"}) 28 | if err != nil { 29 | panic(err) 30 | } 31 | 32 | // create a label selector 33 | selector := labels.NewSelector() 34 | 35 | // adds requirements to the selector 36 | selector = selector.Add(*supportExists, *supportTeam, *partOfReq) 37 | 38 | // print the selector (it will be rendered as in `kubectl label...`) 39 | fmt.Printf("here your selector: %s\n", selector.String()) 40 | } 41 | -------------------------------------------------------------------------------- /using-codegen/pkg/apis/expression/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | "k8s.io/apimachinery/pkg/runtime" 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | ) 8 | 9 | // SchemeGroupVersion is group version used to register these objects 10 | var SchemeGroupVersion = schema.GroupVersion{Group: "example.org", Version: "v1alpha1"} 11 | 12 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 13 | func Kind(kind string) schema.GroupKind { 14 | return SchemeGroupVersion.WithKind(kind).GroupKind() 15 | } 16 | 17 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 18 | func Resource(resource string) schema.GroupResource { 19 | return SchemeGroupVersion.WithResource(resource).GroupResource() 20 | } 21 | 22 | var ( 23 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 24 | AddToScheme = SchemeBuilder.AddToScheme 25 | ) 26 | 27 | // Adds the list of known types to Scheme. 28 | func addKnownTypes(scheme *runtime.Scheme) error { 29 | scheme.AddKnownTypes(SchemeGroupVersion, 30 | &Expression{}, 31 | &ExpressionList{}, 32 | ) 33 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Using client-go 2 | 3 | **Writing Golang clients for talking to a Kubernetes cluster** 4 | 5 | Go source code examples used in [Using `client-go` notebook](https://leanpub.com/using-client-go) are available here. 6 | 7 | If you like the topic and want to support me, you could buy the notebook on [Leanpub](https://leanpub.com/using-client-go) 8 | 9 |     @ 10 | 11 | You can download the notebook TOC and same random page [here](./using-client-go-toc-and-some-random-pages.pdf) 12 | 13 | Thank you! 14 | 15 | -- 16 | 17 | - [Initializing a client](./creating-a-rest-config-instance/) 18 | - [Using `rest.Client`](./using-rest-client/) 19 | - [Using `kubernetes.Clientset`](./using-kubernetes-clientset/) 20 | - [Using `dynamic.Interface`](./using-dynamic-interface/) 21 | - [Using `discovery.DiscoveryClient`](./using-discovery-client/) 22 | - [Using labels and selectors](./labels-and-selectors/) 23 | - [Displaying HTTP API calls](./display-http-calls/) 24 | - [Watching for changes](./watching/) 25 | - [Using `RetryWatcher`](./using-retrywatcher/) 26 | - [Using `SharedInformer`](./using-informers/) 27 | - [Using work queues to write a custom Controller](./workqueue/) 28 | - [Using code generators](./using-codegen/) -------------------------------------------------------------------------------- /using-codegen/hack/hack.go: -------------------------------------------------------------------------------- 1 | //go:build hack 2 | // +build hack 3 | 4 | /* 5 | MIT License 6 | 7 | Copyright (c) 2021 Luca Sepe 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | */ 27 | 28 | package hack 29 | 30 | import _ "k8s.io/code-generator" 31 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | // This package has the automatically generated clientset. 28 | package versioned 29 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | // This package has the automatically generated fake clientset. 28 | package fake 29 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | // This package contains the scheme of the automatically generated clientset. 28 | package scheme 29 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | // Package fake has the automatically generated clients. 28 | package fake 29 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package v1alpha1 28 | 29 | type ExpressionExpansion interface{} 30 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | // This package has the automatically generated typed clients. 28 | package v1alpha1 29 | -------------------------------------------------------------------------------- /using-kubernetes-clientset/deleting-a-deployment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "k8s.io/apimachinery/pkg/api/errors" 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | "k8s.io/client-go/kubernetes" 12 | "k8s.io/client-go/tools/clientcmd" 13 | ) 14 | 15 | func main() { 16 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 17 | if len(defaultKubeconfig) == 0 { 18 | defaultKubeconfig = clientcmd.RecommendedHomeFile 19 | } 20 | 21 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 22 | defaultKubeconfig, "absolute path to the kubeconfig file") 23 | 24 | namespace := flag.String("namespace", metav1.NamespaceDefault, "create the deployment in this namespace") 25 | 26 | flag.Parse() 27 | 28 | // build the config from the specified kubeconfig filepath 29 | config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | // creates a new Clientset for the given config 35 | cs, err := kubernetes.NewForConfig(config) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | // delete the 'nginx' deployment in the namespace 41 | err = cs.AppsV1().Deployments(*namespace). 42 | Delete(context.TODO(), "nginx", metav1.DeleteOptions{}) 43 | if err != nil { 44 | if errors.IsNotFound(err) { 45 | return 46 | } 47 | panic(err.Error()) 48 | } 49 | 50 | fmt.Println("deployment.apps \"nginx\" deleted") 51 | } 52 | -------------------------------------------------------------------------------- /using-dynamic-interface/list-pods/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "k8s.io/apimachinery/pkg/api/errors" 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | "k8s.io/client-go/dynamic" 13 | "k8s.io/client-go/tools/clientcmd" 14 | ) 15 | 16 | func main() { 17 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 18 | if len(defaultKubeconfig) == 0 { 19 | defaultKubeconfig = clientcmd.RecommendedHomeFile 20 | } 21 | 22 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 23 | defaultKubeconfig, "absolute path to the kubeconfig file") 24 | 25 | namespace := flag.String("namespace", metav1.NamespaceDefault, "create the deployment in this namespace") 26 | 27 | flag.Parse() 28 | 29 | rc, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 30 | if err != nil { 31 | panic(err.Error()) 32 | } 33 | 34 | // create a new dynamic client using the rest.Config 35 | dc, err := dynamic.NewForConfig(rc) 36 | if err != nil { 37 | panic(err.Error()) 38 | } 39 | 40 | // identify pods resource 41 | gvr := schema.GroupVersionResource{ 42 | Version: "v1", 43 | Resource: "pods", 44 | } 45 | 46 | // list all pods in the specified namespace 47 | res, err := dc.Resource(gvr). 48 | Namespace(*namespace). 49 | List(context.TODO(), metav1.ListOptions{}) 50 | if err != nil { 51 | if !errors.IsNotFound(err) { 52 | panic(err) 53 | } 54 | } 55 | 56 | // for each pod, print just the name 57 | for _, el := range res.Items { 58 | fmt.Printf("%v\n", el.GetName()) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /labels-and-selectors/list-with-label-selector/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "strings" 9 | 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | "k8s.io/apimachinery/pkg/labels" 12 | "k8s.io/apimachinery/pkg/runtime/schema" 13 | "k8s.io/client-go/dynamic" 14 | "k8s.io/client-go/tools/clientcmd" 15 | ) 16 | 17 | func main() { 18 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 19 | if len(defaultKubeconfig) == 0 { 20 | defaultKubeconfig = clientcmd.RecommendedHomeFile 21 | } 22 | 23 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 24 | defaultKubeconfig, "absolute path to the kubeconfig file") 25 | 26 | flag.Parse() 27 | 28 | rc, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | dc, err := dynamic.NewForConfig(rc) 34 | if err != nil { 35 | panic(err) 36 | } 37 | 38 | var filter string 39 | if len(flag.Args()) > 0 { 40 | sel, err := labels.Parse(strings.Join(flag.Args(), " ")) 41 | if err != nil { 42 | panic(err) 43 | } 44 | filter = sel.String() 45 | } 46 | 47 | gvr := schema.GroupVersionResource{ 48 | Version: "v1", 49 | Resource: "namespaces", 50 | } 51 | 52 | res, err := dc.Resource(gvr). 53 | List(context.TODO(), metav1.ListOptions{LabelSelector: filter}) 54 | if err != nil { 55 | panic(err) 56 | } 57 | 58 | /* 59 | var list corev1.NamespaceList 60 | err = runtime.DefaultUnstructuredConverter.FromUnstructured(res.UnstructuredContent(), &list) 61 | if err != nil { 62 | panic(err) 63 | } 64 | */ 65 | for _, el := range res.Items { 66 | fmt.Println(el.GetName()) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /using-rest-client/deleting-a-deployment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | appsv1 "k8s.io/api/apps/v1" 8 | "k8s.io/apimachinery/pkg/api/errors" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/client-go/kubernetes/scheme" 11 | "k8s.io/client-go/rest" 12 | "k8s.io/client-go/tools/clientcmd" 13 | ) 14 | 15 | func main() { 16 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 17 | clientcmd.NewDefaultClientConfigLoadingRules(), 18 | &clientcmd.ConfigOverrides{}, 19 | ) 20 | 21 | namespace, _, err := configLoader.Namespace() 22 | if err != nil { 23 | panic(err) 24 | } 25 | 26 | cfg, err := configLoader.ClientConfig() 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | // the base API path "/apis" 32 | cfg.APIPath = "apis" 33 | // the Deployment group and version "/apps/v1" 34 | cfg.GroupVersion = &appsv1.SchemeGroupVersion 35 | // specify the serializer 36 | cfg.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 37 | 38 | // create a RESTClient instance, using the the 39 | // configuration object as input parameter 40 | rc, err := rest.RESTClientFor(cfg) 41 | if err != nil { 42 | panic(err.Error()) 43 | } 44 | 45 | // operation result 46 | res := &metav1.Status{} 47 | 48 | // fluent interface to setup and perform the request 49 | // DELETE /apis/apps/v1/namespaces/{namespace}/deployments/{name} 50 | err = rc.Delete(). 51 | Namespace(namespace). 52 | Resource("deployments"). 53 | Name("nginx"). 54 | Do(context.TODO()). 55 | Into(res) 56 | if err != nil { 57 | if errors.IsNotFound(err) { 58 | fmt.Printf("%s\n", err.Error()) 59 | return 60 | } 61 | panic(err.Error()) 62 | } 63 | 64 | fmt.Printf("deployment.apps \"nginx\" delete: %s\n", res.Status) 65 | } 66 | -------------------------------------------------------------------------------- /using-codegen/pkg/apis/expression/v1alpha1/types.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | ) 6 | 7 | // +genclient 8 | // +k8s:deepcopy-gen=true 9 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 10 | 11 | // Expression is our custom resource type. A client is created for it. 12 | type Expression struct { 13 | metav1.TypeMeta `json:",inline"` 14 | 15 | // +optional 16 | metav1.ObjectMeta `json:"metadata,omitempty"` 17 | 18 | Spec ExpressionSpec `json:"spec"` 19 | 20 | // +optional 21 | Status ExpressionStatus `json:"status,omitempty"` 22 | } 23 | 24 | // ExpressionSpec defines the specs for our custom resource 25 | type ExpressionSpec struct { 26 | // Body is the expression. 27 | Body string `json:"body"` 28 | 29 | // Data is the JSON with all the expression variables values- 30 | Data string `json:"data,omitempty"` 31 | } 32 | 33 | // ExpressionStatus define the status of our custom resource 34 | type ExpressionStatus struct { 35 | // Result contains the result of expression evaluation 36 | Result string `json:"result"` 37 | } 38 | 39 | // HasChanged is an utility function to check if two expression are equals. 40 | func (e *Expression) HasChanged(other *Expression) bool { 41 | return e.Spec.Body != other.Spec.Body || e.Spec.Data != other.Spec.Data 42 | } 43 | 44 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 45 | 46 | // ExpressionList is a top-level list type. The client methods for lists are automatically created. 47 | // You are not supposed to create a separated client for this one. 48 | type ExpressionList struct { 49 | metav1.TypeMeta `json:",inline"` 50 | 51 | // +optional 52 | metav1.ListMeta `json:"metadata,omitempty"` 53 | 54 | Items []Expression `json:"items"` 55 | } 56 | -------------------------------------------------------------------------------- /using-dynamic-interface/get-and-update-crds/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "k8s.io/apimachinery/pkg/api/errors" 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | "k8s.io/apimachinery/pkg/runtime/schema" 9 | "k8s.io/client-go/dynamic" 10 | "k8s.io/client-go/tools/clientcmd" 11 | ) 12 | 13 | func main() { 14 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 15 | clientcmd.NewDefaultClientConfigLoadingRules(), 16 | &clientcmd.ConfigOverrides{}, 17 | ) 18 | 19 | namespace, _, err := configLoader.Namespace() 20 | if err != nil { 21 | panic(err) 22 | } 23 | 24 | cfg, err := configLoader.ClientConfig() 25 | if err != nil { 26 | panic(err) 27 | } 28 | 29 | dc, err := dynamic.NewForConfig(cfg) 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | // identify out custom resource 35 | gvr := schema.GroupVersionResource{ 36 | Group: "bella.napoli.it", 37 | Version: "v1alpha1", 38 | Resource: "pizzas", 39 | } 40 | // retrieve the resource of kind Pizza named 'margherita' 41 | res, err := dc.Resource(gvr). 42 | Namespace(namespace). 43 | Get(context.TODO(), "margherita", metav1.GetOptions{}) 44 | if err != nil { 45 | if errors.IsNotFound(err) { 46 | return 47 | } 48 | panic(err) 49 | } 50 | 51 | // grab the status if exists 52 | status, ok := res.Object["status"] 53 | if !ok { 54 | // otherwise create it 55 | status = make(map[string]interface{}) 56 | } 57 | 58 | // change the 'margherita' price 59 | status.(map[string]interface{})["cost"] = 6.50 60 | res.Object["status"] = status 61 | 62 | // update the 'margherita' custom resource with the new price 63 | _, err = dc.Resource(gvr).Namespace(namespace).Update(context.TODO(), res, metav1.UpdateOptions{}) 64 | if err != nil { 65 | panic(err) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /using-kubernetes-clientset/listing-pods/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "strings" 9 | "text/tabwriter" 10 | "time" 11 | 12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | "k8s.io/client-go/kubernetes" 14 | "k8s.io/client-go/tools/clientcmd" 15 | ) 16 | 17 | func main() { 18 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 19 | if len(defaultKubeconfig) == 0 { 20 | defaultKubeconfig = clientcmd.RecommendedHomeFile 21 | } 22 | 23 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 24 | defaultKubeconfig, "absolute path to the kubeconfig file") 25 | 26 | namespace := flag.String("namespace", metav1.NamespaceDefault, "create the deployment in this namespace") 27 | 28 | flag.Parse() 29 | 30 | // build the config from the specified kubeconfig filepath 31 | config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 32 | if err != nil { 33 | panic(err) 34 | } 35 | 36 | // creates a new Clientset for the given config 37 | cs, err := kubernetes.NewForConfig(config) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | // the list of Pods in the namespace 43 | res, err := cs.CoreV1().Pods(*namespace).List(context.TODO(), metav1.ListOptions{}) 44 | if err != nil { 45 | panic(err.Error()) 46 | } 47 | 48 | // print the results on the terminal in the form of a table 49 | w := new(tabwriter.Writer) 50 | w.Init(os.Stdout, 5, 0, 3, ' ', 0) 51 | 52 | dorow := func(cells []string) { 53 | fmt.Fprintln(w, strings.Join(cells, "\t")) 54 | } 55 | 56 | dorow([]string{"NAME", "STATUS", "AGE"}) 57 | 58 | for _, p := range res.Items { 59 | age := time.Since(p.CreationTimestamp.Time).Round(time.Second) 60 | dorow([]string{p.Name, string(p.Status.Phase), fmt.Sprintf("%dm", int(age.Minutes()))}) 61 | } 62 | 63 | w.Flush() 64 | } 65 | -------------------------------------------------------------------------------- /using-codegen/hack/hack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # MIT License 4 | 5 | # Copyright (c) 2021 Luca Sepe 6 | 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | set -o errexit 26 | set -o nounset 27 | set -o pipefail 28 | 29 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 30 | HACK_PKG=${HACK_PKG:-$( 31 | cd "${SCRIPT_ROOT}" 32 | ls -d -1 ../vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator 33 | )} 34 | 35 | # Replace this with your module name 36 | MODULE_ROOT="github.com/lucasepe/using-client-go/using-codegen" 37 | 38 | bash "${HACK_PKG}"/generate-groups.sh "deepcopy,client" \ 39 | ${MODULE_ROOT}/pkg/generated \ 40 | ${MODULE_ROOT}/pkg/apis \ 41 | expression:v1alpha1 \ 42 | --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt 43 | 44 | # Hack to move the generated code in the right place 45 | cp -r ${MODULE_ROOT}/pkg/* ./pkg 46 | rm -rf "github.com" -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/fake/fake_expression_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package fake 28 | 29 | import ( 30 | v1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1" 31 | rest "k8s.io/client-go/rest" 32 | testing "k8s.io/client-go/testing" 33 | ) 34 | 35 | type FakeExampleV1alpha1 struct { 36 | *testing.Fake 37 | } 38 | 39 | func (c *FakeExampleV1alpha1) Expressions(namespace string) v1alpha1.ExpressionInterface { 40 | return &FakeExpressions{c, namespace} 41 | } 42 | 43 | // RESTClient returns a RESTClient that is used to communicate 44 | // with API server by this client implementation. 45 | func (c *FakeExampleV1alpha1) RESTClient() rest.Interface { 46 | var ret *rest.RESTClient 47 | return ret 48 | } 49 | -------------------------------------------------------------------------------- /using-discovery-client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "k8s.io/apimachinery/pkg/util/errors" 8 | "k8s.io/client-go/discovery" 9 | "k8s.io/client-go/tools/clientcmd" 10 | ) 11 | 12 | func main() { 13 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 14 | clientcmd.NewDefaultClientConfigLoadingRules(), 15 | &clientcmd.ConfigOverrides{}, 16 | ) 17 | 18 | rc, err := configLoader.ClientConfig() 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | // create a new DiscoveryClient using the given config 24 | // this client will be used to discover supported resources in the API server 25 | dc, err := discovery.NewDiscoveryClientForConfig(rc) 26 | if err != nil { 27 | panic(err) 28 | } 29 | 30 | // storage for errors 31 | errs := []error{} 32 | 33 | // retrieve the supported resources with the version 34 | // preferred by the server 35 | lists, err := dc.ServerPreferredResources() 36 | if err != nil { 37 | errs = append(errs, err) 38 | } 39 | 40 | // utility struct holding information to print 41 | type info struct { 42 | Kind string `json:"kind"` 43 | APIVersion string `json:"apiVersion"` 44 | Name string `json:"name"` 45 | Verbs []string `json:"verbs"` 46 | } 47 | 48 | // iterate all the APIResource collections 49 | for _, list := range lists { 50 | if len(list.APIResources) == 0 { 51 | continue 52 | } 53 | 54 | // grab the API resource info 55 | for _, el := range list.APIResources { 56 | if len(el.Verbs) == 0 { 57 | continue 58 | } 59 | 60 | tmp := info{el.Kind, list.GroupVersion, el.Name, el.Verbs} 61 | // convert to json... 62 | res, err := json.Marshal(&tmp) 63 | if err != nil { 64 | errs = append(errs, err) 65 | continue 66 | } 67 | //..and print 68 | fmt.Printf("%s\n", res) 69 | } 70 | } 71 | 72 | // if there has been an error 73 | // print it on the screen 74 | if len(errs) > 0 { 75 | panic(errors.NewAggregate(errs)) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /using-dynamic-interface/get-and-update-crds/pizza_crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | # name must match the spec fields below, and be in the form: . 5 | name: pizzas.bella.napoli.it 6 | spec: 7 | # group name to use for REST API: /apis// 8 | group: bella.napoli.it 9 | names: 10 | # kind is normally the CamelCased singular type. Your resource manifests use this. 11 | kind: Pizza 12 | listKind: PizzaList 13 | # plural name to be used in the URL: /apis/// 14 | plural: pizzas 15 | # singular name to be used as an alias on the CLI and for display 16 | singular: pizza 17 | # shortNames allow shorter string to match your resource on the CLI 18 | shortNames: 19 | - piz 20 | # either Namespaced or Cluster 21 | scope: Namespaced 22 | # list of versions supported by this CustomResourceDefinition 23 | versions: 24 | - name: v1alpha1 25 | additionalPrinterColumns: 26 | - jsonPath: .status.cost 27 | description: The Pizza cost 28 | name: Cost (€) 29 | type: number 30 | 31 | schema: 32 | openAPIV3Schema: 33 | type: object 34 | properties: 35 | spec: 36 | properties: 37 | toppings: 38 | description: toppings is a list of Topping names. They don't have 39 | to be unique. Order does not matter. 40 | items: 41 | type: string 42 | type: array 43 | required: 44 | - toppings 45 | type: object 46 | status: 47 | properties: 48 | cost: 49 | description: cost is the cost of the whole pizza including all toppings. 50 | type: number 51 | type: object 52 | type: object 53 | # Each version can be enabled/disabled by Served flag 54 | served: true 55 | # One and only one version must be marked as the storage version 56 | storage: true 57 | 58 | -------------------------------------------------------------------------------- /using-rest-client/listing-pods/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "strings" 8 | "text/tabwriter" 9 | "time" 10 | 11 | corev1 "k8s.io/api/core/v1" 12 | "k8s.io/client-go/kubernetes/scheme" 13 | "k8s.io/client-go/rest" 14 | "k8s.io/client-go/tools/clientcmd" 15 | ) 16 | 17 | func main() { 18 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 19 | clientcmd.NewDefaultClientConfigLoadingRules(), 20 | &clientcmd.ConfigOverrides{}, 21 | ) 22 | 23 | namespace, _, err := configLoader.Namespace() 24 | if err != nil { 25 | panic(err) 26 | } 27 | 28 | cfg, err := configLoader.ClientConfig() 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | // the base API path "/api" (legacy resource) 34 | cfg.APIPath = "api" 35 | // the Pod group and version "/v1" (group name is empty for legacy resources) 36 | cfg.GroupVersion = &corev1.SchemeGroupVersion 37 | // specify the serializer 38 | cfg.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 39 | 40 | // create a RESTClient instance, using the the 41 | // configuration object as input parameter 42 | rc, err := rest.RESTClientFor(cfg) 43 | if err != nil { 44 | panic(err.Error()) 45 | } 46 | 47 | // the list of Pods (the result) 48 | res := &corev1.PodList{} 49 | 50 | // fluent interface to setup and perform 51 | // the GET /api/v1/pods request 52 | err = rc.Get(). 53 | Namespace(namespace). 54 | Resource("pods"). 55 | Do(context.TODO()). 56 | Into(res) 57 | if err != nil { 58 | panic(err.Error()) 59 | } 60 | 61 | // print the results on the terminal in the form of a table 62 | w := new(tabwriter.Writer) 63 | w.Init(os.Stdout, 5, 0, 3, ' ', 0) 64 | 65 | dorow := func(cells []string) { 66 | fmt.Fprintln(w, strings.Join(cells, "\t")) 67 | } 68 | 69 | dorow([]string{"NAME", "STATUS", "AGE"}) 70 | 71 | for _, p := range res.Items { 72 | age := time.Since(p.CreationTimestamp.Time).Round(time.Second) 73 | dorow([]string{p.Name, string(p.Status.Phase), fmt.Sprintf("%dm", int(age.Minutes()))}) 74 | } 75 | 76 | w.Flush() 77 | } 78 | -------------------------------------------------------------------------------- /using-kubernetes-clientset/updating-a-deployment-image/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/types" 11 | "k8s.io/client-go/kubernetes" 12 | "k8s.io/client-go/tools/clientcmd" 13 | ) 14 | 15 | func main() { 16 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 17 | if len(defaultKubeconfig) == 0 { 18 | defaultKubeconfig = clientcmd.RecommendedHomeFile 19 | } 20 | 21 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 22 | defaultKubeconfig, "absolute path to the kubeconfig file") 23 | 24 | namespace := flag.String("namespace", metav1.NamespaceDefault, "create the deployment in this namespace") 25 | 26 | flag.Parse() 27 | 28 | // build the config from the specified kubeconfig filepath 29 | config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | // creates a new Clientset for the given config 35 | cs, err := kubernetes.NewForConfig(config) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | // get the 'nginx' deployment in the namespace 41 | res, err := cs.AppsV1().Deployments(*namespace). 42 | Get(context.TODO(), "nginx", metav1.GetOptions{}) 43 | if err != nil { 44 | panic(err.Error()) 45 | } 46 | 47 | // print the current image (we know that there is only one container) 48 | fmt.Printf("before patching: deployment.apps/%s image is %s\n", 49 | res.Name, res.Spec.Template.Spec.Containers[0].Image) 50 | 51 | // the JSON payload to partially update the specified deployment 52 | patch := []byte(`{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx:1.20.2"}]}}}}`) 53 | 54 | // apply the patch 55 | res, err = cs.AppsV1().Deployments(*namespace). 56 | Patch(context.TODO(), "nginx", types.StrategicMergePatchType, patch, metav1.PatchOptions{}) 57 | if err != nil { 58 | panic(err.Error()) 59 | } 60 | 61 | // print the deployment image after the patch 62 | fmt.Printf("after patching: deployment.apps/%s image is %s\n", 63 | res.Name, res.Spec.Template.Spec.Containers[0].Image) 64 | } 65 | -------------------------------------------------------------------------------- /watching/with-clientset/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | corev1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/types" 10 | "k8s.io/apimachinery/pkg/watch" 11 | "k8s.io/client-go/kubernetes" 12 | "k8s.io/client-go/tools/clientcmd" 13 | ) 14 | 15 | func main() { 16 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 17 | clientcmd.NewDefaultClientConfigLoadingRules(), 18 | &clientcmd.ConfigOverrides{}, 19 | ) 20 | 21 | cfg, err := configLoader.ClientConfig() 22 | if err != nil { 23 | panic(err) 24 | } 25 | 26 | cs, err := kubernetes.NewForConfig(cfg) 27 | if err != nil { 28 | panic(err.Error()) 29 | } 30 | 31 | // utility function to create a int64 pointer 32 | i64Ptr := func(i int64) *int64 { return &i } 33 | 34 | // watch options 35 | opts := metav1.ListOptions{ 36 | TimeoutSeconds: i64Ptr(120), 37 | Watch: true, 38 | } 39 | 40 | // reference to the Namespaces client 41 | nsc := cs.CoreV1().Namespaces() 42 | 43 | // create the watcher 44 | watcher, err := nsc.Watch(context.TODO(), opts) 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | // the patch data, just add a custom label 50 | pd := []byte(`{"metadata":{"labels":{"modified-by":"lucasepe"}}}`) 51 | 52 | // the patch type 53 | pt := types.MergePatchType 54 | 55 | // who did this patch? 56 | po := metav1.PatchOptions{ 57 | FieldManager: "my-cool-app", 58 | } 59 | 60 | // iterate all the events 61 | for event := range watcher.ResultChan() { 62 | // retrieve the Namespace 63 | item := event.Object.(*corev1.Namespace) 64 | 65 | switch event.Type { 66 | 67 | // when a namespace is deleted... 68 | case watch.Deleted: 69 | // let's say hello! 70 | fmt.Printf("- '%s' %v ...bye bye\n", item.GetName(), event.Type) 71 | 72 | // when a namespace is added... 73 | case watch.Added: 74 | fmt.Printf("+ '%s' %v ", item.GetName(), event.Type) 75 | 76 | // try to patch it! 77 | _, err = nsc.Patch(context.TODO(), item.GetName(), pt, pd, po) 78 | if err != nil { 79 | panic(err) 80 | } 81 | 82 | fmt.Println(" ...patched!") 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /using-codegen/manifests/crds/expression-crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | # name must match the spec fields below, and be in the form: . 5 | name: expressions.example.org 6 | spec: 7 | # group name to use for REST API: /apis// 8 | group: example.org 9 | names: 10 | # kind is normally the CamelCased singular type. Your resource manifests use this. 11 | kind: Expression 12 | listKind: ExpressionList 13 | # plural name to be used in the URL: /apis/// 14 | plural: expressions 15 | # singular name to be used as an alias on the CLI and for display 16 | singular: expression 17 | # shortNames allow shorter string to match your resource on the CLI 18 | shortNames: 19 | - exp 20 | # either Namespaced or Cluster 21 | scope: Namespaced 22 | # list of versions supported by this CustomResourceDefinition 23 | versions: 24 | - name: v1alpha1 25 | additionalPrinterColumns: 26 | - jsonPath: .spec.body 27 | description: The expression to evaluate 28 | name: Expression 29 | type: string 30 | - jsonPath: .status.result 31 | description: The evaluation result 32 | name: Result 33 | type: string 34 | schema: 35 | openAPIV3Schema: 36 | type: object 37 | properties: 38 | spec: 39 | properties: 40 | body: 41 | type: string 42 | data: 43 | type: string 44 | required: 45 | - body 46 | - data 47 | type: object 48 | status: 49 | properties: 50 | result: 51 | type: string 52 | error: 53 | type: string 54 | type: object 55 | type: object 56 | # Each version can be enabled/disabled by Served flag 57 | served: true 58 | # One and only one version must be marked as the storage version 59 | storage: true 60 | subresources: 61 | status: {} 62 | status: 63 | acceptedNames: 64 | kind: "" 65 | plural: "" 66 | conditions: [] 67 | storedVersions: [] -------------------------------------------------------------------------------- /using-kubernetes-clientset/creating-a-deployment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | appsv1 "k8s.io/api/apps/v1" 10 | corev1 "k8s.io/api/core/v1" 11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | "k8s.io/client-go/kubernetes" 13 | "k8s.io/client-go/tools/clientcmd" 14 | ) 15 | 16 | func main() { 17 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 18 | if len(defaultKubeconfig) == 0 { 19 | defaultKubeconfig = clientcmd.RecommendedHomeFile 20 | } 21 | 22 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 23 | defaultKubeconfig, "absolute path to the kubeconfig file") 24 | 25 | namespace := flag.String("namespace", metav1.NamespaceDefault, "create the deployment in this namespace") 26 | 27 | flag.Parse() 28 | 29 | // build the config from the specified kubeconfig filepath 30 | config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 31 | if err != nil { 32 | panic(err) 33 | } 34 | 35 | // creates a new Clientset for the given config 36 | cs, err := kubernetes.NewForConfig(config) 37 | if err != nil { 38 | panic(err) 39 | } 40 | 41 | // utility function to create a int32 pointer 42 | i32Ptr := func(i int32) *int32 { return &i } 43 | 44 | // the required request body (a deployment object) 45 | deployment := &appsv1.Deployment{ 46 | ObjectMeta: metav1.ObjectMeta{ 47 | Name: "nginx", 48 | }, 49 | Spec: appsv1.DeploymentSpec{ 50 | Replicas: i32Ptr(1), 51 | Selector: &metav1.LabelSelector{ 52 | MatchLabels: map[string]string{ 53 | "app": "nginx", 54 | }, 55 | }, 56 | Template: corev1.PodTemplateSpec{ 57 | ObjectMeta: metav1.ObjectMeta{ 58 | Labels: map[string]string{ 59 | "app": "nginx", 60 | }, 61 | }, 62 | Spec: corev1.PodSpec{ 63 | Containers: []corev1.Container{ 64 | { 65 | Name: "nginx", 66 | Image: "nginx:1.21.6", 67 | }, 68 | }, 69 | }, 70 | }, 71 | }, 72 | } 73 | 74 | // create the deployment in the specified namespace 75 | res, err := cs.AppsV1().Deployments(*namespace). 76 | Create(context.TODO(), deployment, metav1.CreateOptions{}) 77 | if err != nil { 78 | panic(err.Error()) 79 | } 80 | 81 | fmt.Printf("deployment.apps/%s created\n", res.Name) 82 | } 83 | -------------------------------------------------------------------------------- /using-informers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "time" 8 | 9 | corev1 "k8s.io/api/core/v1" 10 | "k8s.io/client-go/informers" 11 | "k8s.io/client-go/kubernetes" 12 | "k8s.io/client-go/tools/cache" 13 | "k8s.io/client-go/tools/clientcmd" 14 | ) 15 | 16 | func main() { 17 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 18 | if len(defaultKubeconfig) == 0 { 19 | defaultKubeconfig = clientcmd.RecommendedHomeFile 20 | } 21 | 22 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 23 | defaultKubeconfig, "absolute path to the kubeconfig file") 24 | 25 | flag.Parse() 26 | 27 | rc, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 28 | if err != nil { 29 | panic(err.Error()) 30 | } 31 | 32 | // create a client set from config 33 | clientSet, err := kubernetes.NewForConfig(rc) 34 | if err != nil { 35 | panic(err.Error()) 36 | } 37 | 38 | // create a new instance of sharedInformerFactory for all namespaces 39 | informerFactory := informers.NewSharedInformerFactory(clientSet, time.Minute*1) 40 | 41 | // using this factory create an informer for `secret` resources 42 | secretsInformer := informerFactory.Core().V1().Secrets() 43 | 44 | // adds an event handler to the shared informer 45 | secretsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ 46 | AddFunc: func(obj interface{}) { 47 | item := obj.(*corev1.Secret) 48 | fmt.Printf("secret added (ns=%s): %s\n", item.GetNamespace(), item.GetName()) 49 | }, 50 | 51 | UpdateFunc: func(old, new interface{}) { 52 | item := old.(*corev1.Secret) 53 | fmt.Printf("secret updated (ns=%s): %s\n", item.GetNamespace(), item.GetName()) 54 | }, 55 | 56 | DeleteFunc: func(obj interface{}) { 57 | item := obj.(*corev1.Secret) 58 | fmt.Printf("secret deleted (ns=%s): %s\n", item.GetNamespace(), item.GetName()) 59 | }, 60 | }) 61 | 62 | stopCh := make(chan struct{}) 63 | defer close(stopCh) 64 | 65 | // starts the shared informers that have been created by the factory 66 | informerFactory.Start(stopCh) 67 | 68 | // wait for the initial synchronization of the local cache 69 | if !cache.WaitForCacheSync(stopCh, secretsInformer.Informer().HasSynced) { 70 | panic("failed to sync") 71 | } 72 | 73 | // causes the goroutine to block (hit CTRL+C to exit) 74 | select {} 75 | } 76 | -------------------------------------------------------------------------------- /watching/with-dynamic-interface/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 9 | "k8s.io/apimachinery/pkg/runtime/schema" 10 | "k8s.io/apimachinery/pkg/types" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/dynamic" 13 | "k8s.io/client-go/tools/clientcmd" 14 | ) 15 | 16 | func main() { 17 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 18 | clientcmd.NewDefaultClientConfigLoadingRules(), 19 | &clientcmd.ConfigOverrides{}, 20 | ) 21 | 22 | cfg, err := configLoader.ClientConfig() 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | dc, err := dynamic.NewForConfig(cfg) 28 | if err != nil { 29 | panic(err.Error()) 30 | } 31 | 32 | gvr := schema.GroupVersionResource{ 33 | Version: "v1", 34 | Resource: "namespaces", 35 | } 36 | 37 | // utility function to create a int64 pointer 38 | i64Ptr := func(i int64) *int64 { return &i } 39 | 40 | // watch options 41 | opts := metav1.ListOptions{ 42 | TimeoutSeconds: i64Ptr(120), 43 | Watch: true, 44 | } 45 | 46 | // reference to Namespaces resources 47 | nsr := dc.Resource(gvr) 48 | 49 | // create the watcher 50 | watcher, err := nsr.Watch(context.Background(), opts) 51 | if err != nil { 52 | panic(err) 53 | } 54 | 55 | // the patch data, just add a custom label 56 | pd := []byte(`{"metadata":{"labels":{"modified-by":"lucasepe"}}}`) 57 | 58 | // the patch type 59 | pt := types.MergePatchType 60 | 61 | // who did this patch? 62 | po := metav1.PatchOptions{ 63 | FieldManager: "my-cool-app", 64 | } 65 | 66 | // iterate all the events 67 | for event := range watcher.ResultChan() { 68 | // retrieve the Namespace 69 | item := event.Object.(*unstructured.Unstructured) 70 | 71 | switch event.Type { 72 | 73 | // when a namespace is deleted... 74 | case watch.Deleted: 75 | // let's say hello! 76 | fmt.Printf("- '%s' %v ...bye bye\n", item.GetName(), event.Type) 77 | 78 | // when a namespace is added... 79 | case watch.Added: 80 | fmt.Printf("+ '%s' %v ", item.GetName(), event.Type) 81 | 82 | // try to patch it! 83 | _, err = nsr.Patch(context.TODO(), item.GetName(), pt, pd, po) 84 | if err != nil { 85 | panic(err) 86 | } 87 | 88 | fmt.Println(" ...patched!") 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /watching/with-rest-client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/types" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/kubernetes/scheme" 13 | "k8s.io/client-go/rest" 14 | "k8s.io/client-go/tools/clientcmd" 15 | ) 16 | 17 | func main() { 18 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 19 | clientcmd.NewDefaultClientConfigLoadingRules(), 20 | &clientcmd.ConfigOverrides{}, 21 | ) 22 | 23 | cfg, err := configLoader.ClientConfig() 24 | if err != nil { 25 | panic(err) 26 | } 27 | 28 | cfg.APIPath = "/api" 29 | cfg.GroupVersion = &corev1.SchemeGroupVersion 30 | cfg.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 31 | 32 | rc, err := rest.RESTClientFor(cfg) 33 | if err != nil { 34 | panic(err.Error()) 35 | } 36 | 37 | // utility function to create a int64 pointer 38 | i64Ptr := func(i int64) *int64 { return &i } 39 | 40 | opts := metav1.ListOptions{ 41 | TimeoutSeconds: i64Ptr(120), 42 | Watch: true, 43 | } 44 | 45 | watcher, err := rc.Get().Resource("namespaces"). 46 | VersionedParams(&opts, scheme.ParameterCodec). 47 | Timeout(time.Duration(*opts.TimeoutSeconds)). 48 | Watch(context.TODO()) 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | // the patch data, just add a custom label 54 | pd := []byte(`{"metadata":{"labels":{"modified-by":"lucasepe"}}}`) 55 | 56 | // the patch type 57 | pt := types.MergePatchType 58 | 59 | // who did this patch? 60 | po := metav1.PatchOptions{ 61 | FieldManager: "my-cool-app", 62 | } 63 | 64 | // iterate all the events 65 | for event := range watcher.ResultChan() { 66 | // retrieve the Namespace 67 | item := event.Object.(*corev1.Namespace) 68 | 69 | switch event.Type { 70 | 71 | // when a namespace is deleted... 72 | case watch.Deleted: 73 | // let's say hello! 74 | fmt.Printf("- '%s' %v ...bye bye\n", item.GetName(), event.Type) 75 | 76 | // when a namespace is added... 77 | case watch.Added: 78 | fmt.Printf("+ '%s' %v ", item.GetName(), event.Type) 79 | 80 | // try to patch it! 81 | err = rc.Patch(pt).Resource("namespaces"). 82 | Name(item.Name). 83 | VersionedParams(&po, scheme.ParameterCodec). 84 | Body(pd). 85 | Do(context.TODO()). 86 | Error() 87 | if err != nil { 88 | panic(err) 89 | } 90 | 91 | fmt.Println(" ...patched!") 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /using-rest-client/updating-a-deployment-image/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | appsv1 "k8s.io/api/apps/v1" 8 | "k8s.io/apimachinery/pkg/types" 9 | "k8s.io/client-go/kubernetes/scheme" 10 | "k8s.io/client-go/rest" 11 | "k8s.io/client-go/tools/clientcmd" 12 | ) 13 | 14 | func main() { 15 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 16 | clientcmd.NewDefaultClientConfigLoadingRules(), 17 | &clientcmd.ConfigOverrides{}, 18 | ) 19 | 20 | namespace, _, err := configLoader.Namespace() 21 | if err != nil { 22 | panic(err) 23 | } 24 | 25 | cfg, err := configLoader.ClientConfig() 26 | if err != nil { 27 | panic(err) 28 | } 29 | 30 | // the base API path "/apis" 31 | cfg.APIPath = "apis" 32 | // the Deployment group and version "/apps/v1" 33 | cfg.GroupVersion = &appsv1.SchemeGroupVersion 34 | // specify the serializer 35 | cfg.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 36 | 37 | // create a RESTClient instance, using the the configuration object as input parameter 38 | rc, err := rest.RESTClientFor(cfg) 39 | if err != nil { 40 | panic(err.Error()) 41 | } 42 | 43 | // store the operation result here 44 | res := &appsv1.Deployment{} 45 | 46 | // fluent interface to setup and perform the request 47 | // GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} 48 | err = rc.Get(). 49 | Namespace(namespace). 50 | Resource("deployments"). 51 | Name("nginx"). 52 | Do(context.TODO()). 53 | Into(res) // store the result into `res` object 54 | if err != nil { 55 | panic(err.Error()) 56 | } 57 | 58 | // print the current image (we know that there is only one container) 59 | fmt.Printf("before patching: deployment.apps/%s image is %s\n", 60 | res.Name, res.Spec.Template.Spec.Containers[0].Image) 61 | 62 | // the JSON payload to partially update the specified deployment 63 | patch := []byte(`{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx:1.14.2"}]}}}}`) 64 | 65 | // fluent interface to setup and perform the request 66 | // PATCH /apis/apps/v1/namespaces/{namespace}/deployments/{name} 67 | err = rc.Patch(types.StrategicMergePatchType). 68 | Namespace(namespace). 69 | Resource("deployments"). 70 | Name("nginx"). 71 | Body(patch). 72 | Do(context.TODO()). 73 | Into(res) // store the result into `res` object 74 | if err != nil { 75 | panic(err.Error()) 76 | } 77 | 78 | // print the deployment image after the patch 79 | fmt.Printf("after patching: deployment.apps/%s image is %s\n", 80 | res.Name, res.Spec.Template.Spec.Containers[0].Image) 81 | } 82 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package fake 28 | 29 | import ( 30 | examplev1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/apis/expression/v1alpha1" 31 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 | runtime "k8s.io/apimachinery/pkg/runtime" 33 | schema "k8s.io/apimachinery/pkg/runtime/schema" 34 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 35 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 36 | ) 37 | 38 | var scheme = runtime.NewScheme() 39 | var codecs = serializer.NewCodecFactory(scheme) 40 | 41 | var localSchemeBuilder = runtime.SchemeBuilder{ 42 | examplev1alpha1.AddToScheme, 43 | } 44 | 45 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 46 | // of clientsets, like in: 47 | // 48 | // import ( 49 | // "k8s.io/client-go/kubernetes" 50 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 51 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 52 | // ) 53 | // 54 | // kclientset, _ := kubernetes.NewForConfig(c) 55 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 56 | // 57 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 58 | // correctly. 59 | var AddToScheme = localSchemeBuilder.AddToScheme 60 | 61 | func init() { 62 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 63 | utilruntime.Must(AddToScheme(scheme)) 64 | } 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lucasepe/using-client-go 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/PaesslerAG/gval v1.1.2 7 | k8s.io/api v0.23.3 8 | k8s.io/apimachinery v0.23.3 9 | k8s.io/client-go v0.23.3 10 | k8s.io/code-generator v0.23.5 11 | k8s.io/klog/v2 v2.30.0 12 | ) 13 | 14 | require ( 15 | github.com/PuerkitoBio/purell v1.1.1 // indirect 16 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/emicklei/go-restful v2.9.5+incompatible // indirect 19 | github.com/evanphx/json-patch v4.12.0+incompatible // indirect 20 | github.com/go-logr/logr v1.2.0 // indirect 21 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 22 | github.com/go-openapi/jsonreference v0.19.5 // indirect 23 | github.com/go-openapi/swag v0.19.14 // indirect 24 | github.com/gogo/protobuf v1.3.2 // indirect 25 | github.com/golang/protobuf v1.5.2 // indirect 26 | github.com/google/go-cmp v0.5.5 // indirect 27 | github.com/google/gofuzz v1.1.0 // indirect 28 | github.com/googleapis/gnostic v0.5.5 // indirect 29 | github.com/imdario/mergo v0.3.5 // indirect 30 | github.com/josharian/intern v1.0.0 // indirect 31 | github.com/json-iterator/go v1.1.12 // indirect 32 | github.com/mailru/easyjson v0.7.6 // indirect 33 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 34 | github.com/modern-go/reflect2 v1.0.2 // indirect 35 | github.com/pkg/errors v0.9.1 // indirect 36 | github.com/spf13/pflag v1.0.5 // indirect 37 | golang.org/x/mod v0.4.2 // indirect 38 | golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect 39 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect 40 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect 41 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect 42 | golang.org/x/text v0.3.7 // indirect 43 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 44 | golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff // indirect 45 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 46 | google.golang.org/appengine v1.6.7 // indirect 47 | google.golang.org/protobuf v1.27.1 // indirect 48 | gopkg.in/inf.v0 v0.9.1 // indirect 49 | gopkg.in/yaml.v2 v2.4.0 // indirect 50 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 51 | k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect 52 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect 53 | k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect 54 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect 55 | sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect 56 | sigs.k8s.io/yaml v1.2.0 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package scheme 28 | 29 | import ( 30 | examplev1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/apis/expression/v1alpha1" 31 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 | runtime "k8s.io/apimachinery/pkg/runtime" 33 | schema "k8s.io/apimachinery/pkg/runtime/schema" 34 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 35 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 36 | ) 37 | 38 | var Scheme = runtime.NewScheme() 39 | var Codecs = serializer.NewCodecFactory(Scheme) 40 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 41 | var localSchemeBuilder = runtime.SchemeBuilder{ 42 | examplev1alpha1.AddToScheme, 43 | } 44 | 45 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 46 | // of clientsets, like in: 47 | // 48 | // import ( 49 | // "k8s.io/client-go/kubernetes" 50 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 51 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 52 | // ) 53 | // 54 | // kclientset, _ := kubernetes.NewForConfig(c) 55 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 56 | // 57 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 58 | // correctly. 59 | var AddToScheme = localSchemeBuilder.AddToScheme 60 | 61 | func init() { 62 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 63 | utilruntime.Must(AddToScheme(Scheme)) 64 | } 65 | -------------------------------------------------------------------------------- /using-rest-client/creating-a-deployment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | 8 | appsv1 "k8s.io/api/apps/v1" 9 | corev1 "k8s.io/api/core/v1" 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | "k8s.io/client-go/kubernetes/scheme" 12 | "k8s.io/client-go/rest" 13 | "k8s.io/client-go/tools/clientcmd" 14 | ) 15 | 16 | func main() { 17 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 18 | clientcmd.NewDefaultClientConfigLoadingRules(), 19 | &clientcmd.ConfigOverrides{}, 20 | ) 21 | 22 | // Determine the namespace referenced by the 23 | // current context in the kubeconfig file. 24 | namespace, _, err := configLoader.Namespace() 25 | if err != nil { 26 | panic(err) 27 | } 28 | 29 | cfg, err := configLoader.ClientConfig() 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | // POST /apis/apps/v1/namespaces/{namespace}/deployments 35 | 36 | // the base API path "/apis" 37 | cfg.APIPath = "apis" 38 | // the Deployment group and version "/apps/v1" 39 | cfg.GroupVersion = &appsv1.SchemeGroupVersion 40 | // specify the serializer 41 | cfg.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 42 | 43 | // create a RESTClient instance, using the the 44 | // configuration object as input parameter 45 | rc, err := rest.RESTClientFor(cfg) 46 | if err != nil { 47 | panic(err.Error()) 48 | } 49 | 50 | // utility function to create a int32 pointer 51 | i32Ptr := func(i int32) *int32 { return &i } 52 | 53 | // the required request body (a deployment object) 54 | deployment := &appsv1.Deployment{ 55 | ObjectMeta: metav1.ObjectMeta{ 56 | Name: "nginx", 57 | }, 58 | Spec: appsv1.DeploymentSpec{ 59 | Replicas: i32Ptr(1), 60 | Selector: &metav1.LabelSelector{ 61 | MatchLabels: map[string]string{ 62 | "app": "nginx", 63 | }, 64 | }, 65 | Template: corev1.PodTemplateSpec{ 66 | ObjectMeta: metav1.ObjectMeta{ 67 | Labels: map[string]string{ 68 | "app": "nginx", 69 | }, 70 | }, 71 | Spec: corev1.PodSpec{ 72 | Containers: []corev1.Container{ 73 | { 74 | Name: "nginx", 75 | Image: "nginx:1.21.6", 76 | }, 77 | }, 78 | }, 79 | }, 80 | }, 81 | } 82 | 83 | // encode the request payload as JSON 84 | body, err := json.Marshal(deployment) 85 | if err != nil { 86 | panic(err.Error()) 87 | } 88 | 89 | // store the operation result here 90 | res := &appsv1.Deployment{} 91 | 92 | // fluent interface to setup and perform the 93 | // POST /apis/apps/v1/namespaces/{namespace}/deployments request 94 | err = rc.Post(). 95 | Namespace(namespace). 96 | Resource("deployments"). 97 | Body(body). 98 | Do(context.TODO()). 99 | Into(res) // store the result into `res` object 100 | if err != nil { 101 | panic(err.Error()) 102 | } 103 | 104 | fmt.Printf("deployment.apps/%s created\n", res.Name) 105 | } 106 | -------------------------------------------------------------------------------- /using-codegen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "strings" 10 | 11 | "k8s.io/client-go/tools/clientcmd" 12 | 13 | "github.com/PaesslerAG/gval" 14 | 15 | expressionV1alpha1Api "github.com/lucasepe/using-client-go/using-codegen/pkg/apis/expression/v1alpha1" 16 | expressionV1alpha1Clientset "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned" 17 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 | ) 19 | 20 | func main() { 21 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 22 | if len(defaultKubeconfig) == 0 { 23 | defaultKubeconfig = clientcmd.RecommendedHomeFile 24 | } 25 | 26 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 27 | defaultKubeconfig, "absolute path to the kubeconfig file") 28 | 29 | namespace := flag.String("namespace", metav1.NamespaceDefault, "create the deployment in this namespace") 30 | 31 | flag.Usage = func() { 32 | name := os.Args[0] 33 | if strings.Contains(name, "go-build") { 34 | name = "go run main.go" 35 | } 36 | 37 | w := flag.CommandLine.Output() 38 | fmt.Fprintf(w, "Usage: %s \n\n", name) 39 | 40 | fmt.Fprintf(w, "Flags:\n") 41 | flag.PrintDefaults() 42 | } 43 | 44 | flag.Parse() 45 | 46 | if len(flag.Args()) == 0 { 47 | flag.Usage() 48 | os.Exit(1) 49 | } 50 | 51 | // build the config from the specified kubeconfig filepath 52 | cfg, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 53 | if err != nil { 54 | panic(err) 55 | } 56 | 57 | cs, err := expressionV1alpha1Clientset.NewForConfig(cfg) 58 | if err != nil { 59 | panic(err) 60 | } 61 | 62 | res, err := cs.ExampleV1alpha1().Expressions(*namespace). 63 | Get(context.TODO(), flag.Args()[0], metav1.GetOptions{}) 64 | if err != nil { 65 | panic(err) 66 | } 67 | 68 | val, err := evalExpression(res) 69 | if err != nil { 70 | panic(err) 71 | } 72 | res.Status.Result = strval(val) 73 | 74 | _, err = cs.ExampleV1alpha1().Expressions(*namespace). 75 | UpdateStatus(context.TODO(), res, metav1.UpdateOptions{}) 76 | if err != nil { 77 | panic(err) 78 | } 79 | 80 | fmt.Printf("Expression evaluated! Type 'kubectl get exp %s' to check the result.\n", flag.Args()[0]) 81 | } 82 | 83 | func evalExpression(src *expressionV1alpha1Api.Expression) (string, error) { 84 | var data map[string]interface{} 85 | err := json.Unmarshal([]byte(src.Spec.Data), &data) 86 | if err != nil { 87 | return err.Error(), err 88 | } 89 | 90 | val, err := gval.Evaluate(src.Spec.Body, data) 91 | if err != nil { 92 | return err.Error(), err 93 | } 94 | 95 | return strval(val), nil 96 | } 97 | 98 | func strval(v interface{}) string { 99 | switch v := v.(type) { 100 | case string: 101 | return v 102 | case []byte: 103 | return string(v) 104 | case error: 105 | return v.Error() 106 | case fmt.Stringer: 107 | return v.String() 108 | default: 109 | return fmt.Sprintf("%v", v) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /using-retrywatcher/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | apiWatch "k8s.io/apimachinery/pkg/watch" 11 | "k8s.io/client-go/kubernetes" 12 | "k8s.io/client-go/tools/cache" 13 | "k8s.io/client-go/tools/clientcmd" 14 | "k8s.io/client-go/tools/watch" 15 | ) 16 | 17 | // sentinel is an object that knows how to 18 | // start a watch on namespaces resources 19 | // 20 | // this is our implementation of `cache.Watcher` 21 | type sentinel struct { 22 | client *kubernetes.Clientset 23 | timeoutSecs int64 24 | } 25 | 26 | // newSentinel returns a new `sentinel` object that implements `cache.Watcher` 27 | func newSentinel(cs *kubernetes.Clientset, timeout int64) cache.Watcher { 28 | return &sentinel{cs, timeout} 29 | } 30 | 31 | // Watch begin a watch on namespaces resources 32 | func (s *sentinel) Watch(options metav1.ListOptions) (apiWatch.Interface, error) { 33 | return s.client.CoreV1().Namespaces(). 34 | Watch(context.Background(), metav1.ListOptions{ 35 | TimeoutSeconds: &s.timeoutSecs, 36 | }) 37 | } 38 | 39 | // just to be sure that `cache.Watcher` interface 40 | // is being implemented by our `sentinel` struct type 41 | var _ cache.Watcher = (*sentinel)(nil) 42 | 43 | func main() { 44 | configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 45 | clientcmd.NewDefaultClientConfigLoadingRules(), 46 | &clientcmd.ConfigOverrides{}, 47 | ) 48 | 49 | cfg, err := configLoader.ClientConfig() 50 | if err != nil { 51 | panic(err) 52 | } 53 | 54 | // create a new `Clientset`` for the given config 55 | cs, err := kubernetes.NewForConfig(cfg) 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | fmt.Printf("---- Start watching namespaces ----\n") 61 | 62 | // create a `cache.Watcher` implementation using the `ClientSet`` 63 | watcher := newSentinel(cs, 50) 64 | // create a `RetryWatcher` using initial 65 | // version "1" and our specialized watcher 66 | rw, err := watch.NewRetryWatcher("1", watcher) 67 | if err != nil { 68 | panic(err) 69 | } 70 | 71 | // process incoming event notifications 72 | for { 73 | // grab the event object 74 | event, ok := <-rw.ResultChan() 75 | if !ok { 76 | panic(fmt.Errorf("closed channel")) 77 | } 78 | 79 | // cast to namespace 80 | ns, ok := event.Object.(*corev1.Namespace) 81 | if !ok { 82 | panic(fmt.Errorf("invalid type '%T'", event.Object)) 83 | } 84 | 85 | // skip events older then five minutes 86 | creationTime := ns.GetCreationTimestamp().Time 87 | fiveMinsAgo := time.Now().Add(-5 * time.Minute) 88 | if event.Type == apiWatch.Added && creationTime.Before(fiveMinsAgo) { 89 | // fmt.Printf(">> skip older events (creationTime: %s, currentTime: %s)\n", 90 | // creationTime.Format(time.RFC3339), time.Now().Format(time.RFC3339)) 91 | continue 92 | } 93 | 94 | // print some info about the event 95 | fmt.Printf("%s %s (createdAt: %s, phase: %s)\n", 96 | event.Type, ns.Name, creationTime.Format(time.RFC3339), ns.Status.Phase) 97 | 98 | // sleep a bit 99 | time.Sleep(5 * time.Second) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /display-http-calls/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "net/http" 8 | "net/http/httputil" 9 | "os" 10 | 11 | "k8s.io/apimachinery/pkg/api/errors" 12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | "k8s.io/apimachinery/pkg/runtime/schema" 14 | "k8s.io/client-go/dynamic" 15 | "k8s.io/client-go/tools/clientcmd" 16 | ) 17 | 18 | // Tracer implements http.RoundTripper. It prints each request and 19 | // response/error to os.Stderr. WARNING: this may output sensitive information 20 | // including bearer tokens. 21 | type Tracer struct { 22 | http.RoundTripper 23 | } 24 | 25 | // RoundTrip calls the nested RoundTripper while printing each request and 26 | // response/error to os.Stderr on either side of the nested call. WARNING: this 27 | // may output sensitive information including bearer tokens. 28 | func (t *Tracer) RoundTrip(req *http.Request) (*http.Response, error) { 29 | // Dump the request to os.Stderr. 30 | b, err := httputil.DumpRequestOut(req, true) 31 | if err != nil { 32 | return nil, err 33 | } 34 | os.Stderr.Write(b) 35 | os.Stderr.Write([]byte{'\n'}) 36 | 37 | // Call the nested RoundTripper. 38 | resp, err := t.RoundTripper.RoundTrip(req) 39 | 40 | // If an error was returned, dump it to os.Stderr. 41 | if err != nil { 42 | fmt.Fprintln(os.Stderr, err) 43 | return resp, err 44 | } 45 | 46 | // Dump the response to os.Stderr. 47 | b, err = httputil.DumpResponse(resp, req.URL.Query().Get("watch") != "true") 48 | if err != nil { 49 | return nil, err 50 | } 51 | os.Stderr.Write(b) 52 | os.Stderr.Write([]byte{'\n'}) 53 | 54 | return resp, err 55 | } 56 | 57 | // go run main.go -namespace kube-system 58 | func main() { 59 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 60 | if len(defaultKubeconfig) == 0 { 61 | defaultKubeconfig = clientcmd.RecommendedHomeFile 62 | } 63 | 64 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 65 | defaultKubeconfig, "absolute path to the kubeconfig file") 66 | 67 | namespace := flag.String("namespace", metav1.NamespaceDefault, 68 | "create the deployment in this namespace") 69 | 70 | verbose := flag.Bool("verbose", false, "display HTTP calls") 71 | 72 | flag.Parse() 73 | 74 | rc, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 75 | if err != nil { 76 | panic(err.Error()) 77 | } 78 | 79 | if *verbose { 80 | // wrap the default RoundTripper with an instance of Tracer. 81 | rc.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { 82 | return &Tracer{rt} 83 | } 84 | } 85 | 86 | // create a new dynamic client using the rest.Config 87 | dc, err := dynamic.NewForConfig(rc) 88 | if err != nil { 89 | panic(err.Error()) 90 | } 91 | 92 | // identify pods resource 93 | gvr := schema.GroupVersionResource{ 94 | Version: "v1", 95 | Resource: "pods", 96 | } 97 | 98 | // list all pods in the specified namespace 99 | res, err := dc.Resource(gvr). 100 | Namespace(*namespace). 101 | List(context.TODO(), metav1.ListOptions{}) 102 | if err != nil { 103 | if !errors.IsNotFound(err) { 104 | panic(err) 105 | } 106 | } 107 | 108 | // for each pod, print just the name 109 | for _, el := range res.Items { 110 | fmt.Printf("%v\n", el.GetName()) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package fake 28 | 29 | import ( 30 | clientset "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned" 31 | examplev1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1" 32 | fakeexamplev1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/fake" 33 | "k8s.io/apimachinery/pkg/runtime" 34 | "k8s.io/apimachinery/pkg/watch" 35 | "k8s.io/client-go/discovery" 36 | fakediscovery "k8s.io/client-go/discovery/fake" 37 | "k8s.io/client-go/testing" 38 | ) 39 | 40 | // NewSimpleClientset returns a clientset that will respond with the provided objects. 41 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, 42 | // without applying any validations and/or defaults. It shouldn't be considered a replacement 43 | // for a real clientset and is mostly useful in simple unit tests. 44 | func NewSimpleClientset(objects ...runtime.Object) *Clientset { 45 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) 46 | for _, obj := range objects { 47 | if err := o.Add(obj); err != nil { 48 | panic(err) 49 | } 50 | } 51 | 52 | cs := &Clientset{tracker: o} 53 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} 54 | cs.AddReactor("*", "*", testing.ObjectReaction(o)) 55 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { 56 | gvr := action.GetResource() 57 | ns := action.GetNamespace() 58 | watch, err := o.Watch(gvr, ns) 59 | if err != nil { 60 | return false, nil, err 61 | } 62 | return true, watch, nil 63 | }) 64 | 65 | return cs 66 | } 67 | 68 | // Clientset implements clientset.Interface. Meant to be embedded into a 69 | // struct to get a default implementation. This makes faking out just the method 70 | // you want to test easier. 71 | type Clientset struct { 72 | testing.Fake 73 | discovery *fakediscovery.FakeDiscovery 74 | tracker testing.ObjectTracker 75 | } 76 | 77 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 78 | return c.discovery 79 | } 80 | 81 | func (c *Clientset) Tracker() testing.ObjectTracker { 82 | return c.tracker 83 | } 84 | 85 | var ( 86 | _ clientset.Interface = &Clientset{} 87 | _ testing.FakeClient = &Clientset{} 88 | ) 89 | 90 | // ExampleV1alpha1 retrieves the ExampleV1alpha1Client 91 | func (c *Clientset) ExampleV1alpha1() examplev1alpha1.ExampleV1alpha1Interface { 92 | return &fakeexamplev1alpha1.FakeExampleV1alpha1{Fake: &c.Fake} 93 | } 94 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/expression_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package v1alpha1 28 | 29 | import ( 30 | "net/http" 31 | 32 | v1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/apis/expression/v1alpha1" 33 | "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned/scheme" 34 | rest "k8s.io/client-go/rest" 35 | ) 36 | 37 | type ExampleV1alpha1Interface interface { 38 | RESTClient() rest.Interface 39 | ExpressionsGetter 40 | } 41 | 42 | // ExampleV1alpha1Client is used to interact with features provided by the example.org group. 43 | type ExampleV1alpha1Client struct { 44 | restClient rest.Interface 45 | } 46 | 47 | func (c *ExampleV1alpha1Client) Expressions(namespace string) ExpressionInterface { 48 | return newExpressions(c, namespace) 49 | } 50 | 51 | // NewForConfig creates a new ExampleV1alpha1Client for the given config. 52 | // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), 53 | // where httpClient was generated with rest.HTTPClientFor(c). 54 | func NewForConfig(c *rest.Config) (*ExampleV1alpha1Client, error) { 55 | config := *c 56 | if err := setConfigDefaults(&config); err != nil { 57 | return nil, err 58 | } 59 | httpClient, err := rest.HTTPClientFor(&config) 60 | if err != nil { 61 | return nil, err 62 | } 63 | return NewForConfigAndClient(&config, httpClient) 64 | } 65 | 66 | // NewForConfigAndClient creates a new ExampleV1alpha1Client for the given config and http client. 67 | // Note the http client provided takes precedence over the configured transport values. 68 | func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExampleV1alpha1Client, error) { 69 | config := *c 70 | if err := setConfigDefaults(&config); err != nil { 71 | return nil, err 72 | } 73 | client, err := rest.RESTClientForConfigAndClient(&config, h) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return &ExampleV1alpha1Client{client}, nil 78 | } 79 | 80 | // NewForConfigOrDie creates a new ExampleV1alpha1Client for the given config and 81 | // panics if there is an error in the config. 82 | func NewForConfigOrDie(c *rest.Config) *ExampleV1alpha1Client { 83 | client, err := NewForConfig(c) 84 | if err != nil { 85 | panic(err) 86 | } 87 | return client 88 | } 89 | 90 | // New creates a new ExampleV1alpha1Client for the given RESTClient. 91 | func New(c rest.Interface) *ExampleV1alpha1Client { 92 | return &ExampleV1alpha1Client{c} 93 | } 94 | 95 | func setConfigDefaults(config *rest.Config) error { 96 | gv := v1alpha1.SchemeGroupVersion 97 | config.GroupVersion = &gv 98 | config.APIPath = "/apis" 99 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 100 | 101 | if config.UserAgent == "" { 102 | config.UserAgent = rest.DefaultKubernetesUserAgent() 103 | } 104 | 105 | return nil 106 | } 107 | 108 | // RESTClient returns a RESTClient that is used to communicate 109 | // with API server by this client implementation. 110 | func (c *ExampleV1alpha1Client) RESTClient() rest.Interface { 111 | if c == nil { 112 | return nil 113 | } 114 | return c.restClient 115 | } 116 | -------------------------------------------------------------------------------- /using-codegen/pkg/apis/expression/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright (c) 2022 6 | 7 | Permission is hereby granted, free of charge, to any person 8 | obtaining a copy of this software and associated documentation 9 | files (the "Software"), to deal in the Software without 10 | restriction, including without limitation the rights to use, 11 | copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the 13 | Software is furnished to do so, subject to the following 14 | conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | // Code generated by deepcopy-gen. DO NOT EDIT. 29 | 30 | package v1alpha1 31 | 32 | import ( 33 | runtime "k8s.io/apimachinery/pkg/runtime" 34 | ) 35 | 36 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 37 | func (in *Expression) DeepCopyInto(out *Expression) { 38 | *out = *in 39 | out.TypeMeta = in.TypeMeta 40 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 41 | out.Spec = in.Spec 42 | out.Status = in.Status 43 | return 44 | } 45 | 46 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Expression. 47 | func (in *Expression) DeepCopy() *Expression { 48 | if in == nil { 49 | return nil 50 | } 51 | out := new(Expression) 52 | in.DeepCopyInto(out) 53 | return out 54 | } 55 | 56 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 57 | func (in *Expression) DeepCopyObject() runtime.Object { 58 | if c := in.DeepCopy(); c != nil { 59 | return c 60 | } 61 | return nil 62 | } 63 | 64 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 65 | func (in *ExpressionList) DeepCopyInto(out *ExpressionList) { 66 | *out = *in 67 | out.TypeMeta = in.TypeMeta 68 | in.ListMeta.DeepCopyInto(&out.ListMeta) 69 | if in.Items != nil { 70 | in, out := &in.Items, &out.Items 71 | *out = make([]Expression, len(*in)) 72 | for i := range *in { 73 | (*in)[i].DeepCopyInto(&(*out)[i]) 74 | } 75 | } 76 | return 77 | } 78 | 79 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpressionList. 80 | func (in *ExpressionList) DeepCopy() *ExpressionList { 81 | if in == nil { 82 | return nil 83 | } 84 | out := new(ExpressionList) 85 | in.DeepCopyInto(out) 86 | return out 87 | } 88 | 89 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 90 | func (in *ExpressionList) DeepCopyObject() runtime.Object { 91 | if c := in.DeepCopy(); c != nil { 92 | return c 93 | } 94 | return nil 95 | } 96 | 97 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 98 | func (in *ExpressionSpec) DeepCopyInto(out *ExpressionSpec) { 99 | *out = *in 100 | return 101 | } 102 | 103 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpressionSpec. 104 | func (in *ExpressionSpec) DeepCopy() *ExpressionSpec { 105 | if in == nil { 106 | return nil 107 | } 108 | out := new(ExpressionSpec) 109 | in.DeepCopyInto(out) 110 | return out 111 | } 112 | 113 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 114 | func (in *ExpressionStatus) DeepCopyInto(out *ExpressionStatus) { 115 | *out = *in 116 | return 117 | } 118 | 119 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpressionStatus. 120 | func (in *ExpressionStatus) DeepCopy() *ExpressionStatus { 121 | if in == nil { 122 | return nil 123 | } 124 | out := new(ExpressionStatus) 125 | in.DeepCopyInto(out) 126 | return out 127 | } 128 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/clientset.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package versioned 28 | 29 | import ( 30 | "fmt" 31 | "net/http" 32 | 33 | examplev1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1" 34 | discovery "k8s.io/client-go/discovery" 35 | rest "k8s.io/client-go/rest" 36 | flowcontrol "k8s.io/client-go/util/flowcontrol" 37 | ) 38 | 39 | type Interface interface { 40 | Discovery() discovery.DiscoveryInterface 41 | ExampleV1alpha1() examplev1alpha1.ExampleV1alpha1Interface 42 | } 43 | 44 | // Clientset contains the clients for groups. Each group has exactly one 45 | // version included in a Clientset. 46 | type Clientset struct { 47 | *discovery.DiscoveryClient 48 | exampleV1alpha1 *examplev1alpha1.ExampleV1alpha1Client 49 | } 50 | 51 | // ExampleV1alpha1 retrieves the ExampleV1alpha1Client 52 | func (c *Clientset) ExampleV1alpha1() examplev1alpha1.ExampleV1alpha1Interface { 53 | return c.exampleV1alpha1 54 | } 55 | 56 | // Discovery retrieves the DiscoveryClient 57 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 58 | if c == nil { 59 | return nil 60 | } 61 | return c.DiscoveryClient 62 | } 63 | 64 | // NewForConfig creates a new Clientset for the given config. 65 | // If config's RateLimiter is not set and QPS and Burst are acceptable, 66 | // NewForConfig will generate a rate-limiter in configShallowCopy. 67 | // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), 68 | // where httpClient was generated with rest.HTTPClientFor(c). 69 | func NewForConfig(c *rest.Config) (*Clientset, error) { 70 | configShallowCopy := *c 71 | 72 | // share the transport between all clients 73 | httpClient, err := rest.HTTPClientFor(&configShallowCopy) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | return NewForConfigAndClient(&configShallowCopy, httpClient) 79 | } 80 | 81 | // NewForConfigAndClient creates a new Clientset for the given config and http client. 82 | // Note the http client provided takes precedence over the configured transport values. 83 | // If config's RateLimiter is not set and QPS and Burst are acceptable, 84 | // NewForConfigAndClient will generate a rate-limiter in configShallowCopy. 85 | func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { 86 | configShallowCopy := *c 87 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { 88 | if configShallowCopy.Burst <= 0 { 89 | return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") 90 | } 91 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) 92 | } 93 | 94 | var cs Clientset 95 | var err error 96 | cs.exampleV1alpha1, err = examplev1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) 102 | if err != nil { 103 | return nil, err 104 | } 105 | return &cs, nil 106 | } 107 | 108 | // NewForConfigOrDie creates a new Clientset for the given config and 109 | // panics if there is an error in the config. 110 | func NewForConfigOrDie(c *rest.Config) *Clientset { 111 | cs, err := NewForConfig(c) 112 | if err != nil { 113 | panic(err) 114 | } 115 | return cs 116 | } 117 | 118 | // New creates a new Clientset for the given RESTClient. 119 | func New(c rest.Interface) *Clientset { 120 | var cs Clientset 121 | cs.exampleV1alpha1 = examplev1alpha1.New(c) 122 | 123 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c) 124 | return &cs 125 | } 126 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/fake/fake_expression.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package fake 28 | 29 | import ( 30 | "context" 31 | 32 | v1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/apis/expression/v1alpha1" 33 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 | labels "k8s.io/apimachinery/pkg/labels" 35 | schema "k8s.io/apimachinery/pkg/runtime/schema" 36 | types "k8s.io/apimachinery/pkg/types" 37 | watch "k8s.io/apimachinery/pkg/watch" 38 | testing "k8s.io/client-go/testing" 39 | ) 40 | 41 | // FakeExpressions implements ExpressionInterface 42 | type FakeExpressions struct { 43 | Fake *FakeExampleV1alpha1 44 | ns string 45 | } 46 | 47 | var expressionsResource = schema.GroupVersionResource{Group: "example.org", Version: "v1alpha1", Resource: "expressions"} 48 | 49 | var expressionsKind = schema.GroupVersionKind{Group: "example.org", Version: "v1alpha1", Kind: "Expression"} 50 | 51 | // Get takes name of the expression, and returns the corresponding expression object, and an error if there is any. 52 | func (c *FakeExpressions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Expression, err error) { 53 | obj, err := c.Fake. 54 | Invokes(testing.NewGetAction(expressionsResource, c.ns, name), &v1alpha1.Expression{}) 55 | 56 | if obj == nil { 57 | return nil, err 58 | } 59 | return obj.(*v1alpha1.Expression), err 60 | } 61 | 62 | // List takes label and field selectors, and returns the list of Expressions that match those selectors. 63 | func (c *FakeExpressions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ExpressionList, err error) { 64 | obj, err := c.Fake. 65 | Invokes(testing.NewListAction(expressionsResource, expressionsKind, c.ns, opts), &v1alpha1.ExpressionList{}) 66 | 67 | if obj == nil { 68 | return nil, err 69 | } 70 | 71 | label, _, _ := testing.ExtractFromListOptions(opts) 72 | if label == nil { 73 | label = labels.Everything() 74 | } 75 | list := &v1alpha1.ExpressionList{ListMeta: obj.(*v1alpha1.ExpressionList).ListMeta} 76 | for _, item := range obj.(*v1alpha1.ExpressionList).Items { 77 | if label.Matches(labels.Set(item.Labels)) { 78 | list.Items = append(list.Items, item) 79 | } 80 | } 81 | return list, err 82 | } 83 | 84 | // Watch returns a watch.Interface that watches the requested expressions. 85 | func (c *FakeExpressions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { 86 | return c.Fake. 87 | InvokesWatch(testing.NewWatchAction(expressionsResource, c.ns, opts)) 88 | 89 | } 90 | 91 | // Create takes the representation of a expression and creates it. Returns the server's representation of the expression, and an error, if there is any. 92 | func (c *FakeExpressions) Create(ctx context.Context, expression *v1alpha1.Expression, opts v1.CreateOptions) (result *v1alpha1.Expression, err error) { 93 | obj, err := c.Fake. 94 | Invokes(testing.NewCreateAction(expressionsResource, c.ns, expression), &v1alpha1.Expression{}) 95 | 96 | if obj == nil { 97 | return nil, err 98 | } 99 | return obj.(*v1alpha1.Expression), err 100 | } 101 | 102 | // Update takes the representation of a expression and updates it. Returns the server's representation of the expression, and an error, if there is any. 103 | func (c *FakeExpressions) Update(ctx context.Context, expression *v1alpha1.Expression, opts v1.UpdateOptions) (result *v1alpha1.Expression, err error) { 104 | obj, err := c.Fake. 105 | Invokes(testing.NewUpdateAction(expressionsResource, c.ns, expression), &v1alpha1.Expression{}) 106 | 107 | if obj == nil { 108 | return nil, err 109 | } 110 | return obj.(*v1alpha1.Expression), err 111 | } 112 | 113 | // UpdateStatus was generated because the type contains a Status member. 114 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 115 | func (c *FakeExpressions) UpdateStatus(ctx context.Context, expression *v1alpha1.Expression, opts v1.UpdateOptions) (*v1alpha1.Expression, error) { 116 | obj, err := c.Fake. 117 | Invokes(testing.NewUpdateSubresourceAction(expressionsResource, "status", c.ns, expression), &v1alpha1.Expression{}) 118 | 119 | if obj == nil { 120 | return nil, err 121 | } 122 | return obj.(*v1alpha1.Expression), err 123 | } 124 | 125 | // Delete takes name of the expression and deletes it. Returns an error if one occurs. 126 | func (c *FakeExpressions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { 127 | _, err := c.Fake. 128 | Invokes(testing.NewDeleteActionWithOptions(expressionsResource, c.ns, name, opts), &v1alpha1.Expression{}) 129 | 130 | return err 131 | } 132 | 133 | // DeleteCollection deletes a collection of objects. 134 | func (c *FakeExpressions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { 135 | action := testing.NewDeleteCollectionAction(expressionsResource, c.ns, listOpts) 136 | 137 | _, err := c.Fake.Invokes(action, &v1alpha1.ExpressionList{}) 138 | return err 139 | } 140 | 141 | // Patch applies the patch and returns the patched expression. 142 | func (c *FakeExpressions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Expression, err error) { 143 | obj, err := c.Fake. 144 | Invokes(testing.NewPatchSubresourceAction(expressionsResource, c.ns, name, pt, data, subresources...), &v1alpha1.Expression{}) 145 | 146 | if obj == nil { 147 | return nil, err 148 | } 149 | return obj.(*v1alpha1.Expression), err 150 | } 151 | -------------------------------------------------------------------------------- /workqueue/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "time" 9 | 10 | "k8s.io/klog/v2" 11 | 12 | corev1 "k8s.io/api/core/v1" 13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | "k8s.io/apimachinery/pkg/runtime" 15 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 16 | "k8s.io/apimachinery/pkg/util/wait" 17 | "k8s.io/apimachinery/pkg/watch" 18 | "k8s.io/client-go/kubernetes" 19 | "k8s.io/client-go/tools/cache" 20 | "k8s.io/client-go/tools/clientcmd" 21 | "k8s.io/client-go/util/workqueue" 22 | ) 23 | 24 | // Controller demonstrates how to implement a controller with client-go. 25 | type Controller struct { 26 | queue workqueue.RateLimitingInterface 27 | informer cache.SharedInformer 28 | } 29 | 30 | // NewController creates a new Controller. 31 | func NewController( 32 | queue workqueue.RateLimitingInterface, 33 | informer cache.SharedInformer) *Controller { 34 | return &Controller{ 35 | informer: informer, 36 | queue: queue, 37 | } 38 | } 39 | 40 | func (c *Controller) processNextItem() bool { 41 | // Wait until there is a new item in the working queue 42 | key, quit := c.queue.Get() 43 | if quit { 44 | return false 45 | } 46 | // Tell the queue that we are done with processing this key. 47 | // - unblocks the key for other workers 48 | // - allows safe parallel processing because two pods with 49 | // the same key are never processed in parallel 50 | defer c.queue.Done(key) 51 | 52 | // Invoke the method containing the business logic 53 | err := c.syncToStdout(key.(string)) 54 | 55 | // Handle the error if something went wrong during 56 | // the execution of the business logic 57 | c.handleErr(err, key) 58 | 59 | return true 60 | } 61 | 62 | // syncToStdout is the business logic of the controller. 63 | // This controller simply prints information about the pod to stdout. 64 | // In case an error happened, it has to simply return the error. 65 | // The retry logic should not be part of the business logic. 66 | func (c *Controller) syncToStdout(key string) error { 67 | obj, exists, err := c.informer.GetStore().GetByKey(key) 68 | if err != nil { 69 | klog.Errorf("Fetching object with key %s from store failed with %v", key, err) 70 | return err 71 | } 72 | 73 | if !exists { 74 | fmt.Printf("Pod %s does not exist anymore\n", key) 75 | } else { 76 | fmt.Printf("Sync/Add/Update for Pod %s\n", obj.(*corev1.Pod).GetName()) 77 | } 78 | 79 | return nil 80 | } 81 | 82 | // handleErr checks if an error happened and makes sure we will retry later. 83 | func (c *Controller) handleErr(err error, key interface{}) { 84 | if err == nil { 85 | // Forget about the #AddRateLimited history of the key 86 | // on every successful synchronization. 87 | // This ensures that future processing of updates for 88 | // this key is not delayed because of an outdated error history. 89 | c.queue.Forget(key) 90 | return 91 | } 92 | 93 | // This controller retries 5 times if something goes wrong. 94 | // After that, it stops trying. 95 | if c.queue.NumRequeues(key) < 5 { 96 | klog.Infof("Error syncing pod %v: %v", key, err) 97 | 98 | // Re-enqueue the key rate limited. Based on the rate limiter on the 99 | // queue and the re-enqueue history, the key will be processed later again. 100 | c.queue.AddRateLimited(key) 101 | 102 | return 103 | } 104 | 105 | c.queue.Forget(key) 106 | 107 | // Report to an external entity that, even after 108 | // several retries, we could not successfully process this key. 109 | utilruntime.HandleError(err) 110 | 111 | klog.Infof("Dropping pod %q out of the queue: %v", key, err) 112 | } 113 | 114 | // Run begins watching and syncing. 115 | func (c *Controller) Run(workers int, stopCh chan struct{}) { 116 | // eventually catches a crash and logs an error 117 | defer utilruntime.HandleCrash() 118 | 119 | // Let the workers stop when we are done 120 | defer c.queue.ShutDown() 121 | klog.Info("Starting Pod controller") 122 | 123 | go c.informer.Run(stopCh) 124 | 125 | // Wait for all involved caches to be synced, before 126 | // processing items from the queue is started 127 | if !cache.WaitForCacheSync(stopCh, c.informer.HasSynced) { 128 | utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync")) 129 | return 130 | } 131 | 132 | for i := 0; i < workers; i++ { 133 | go wait.Until(c.runWorker, time.Second, stopCh) 134 | } 135 | 136 | <-stopCh 137 | klog.Info("Stopping Pod controller") 138 | } 139 | 140 | func (c *Controller) runWorker() { 141 | for c.processNextItem() { 142 | } 143 | } 144 | 145 | func main() { 146 | defaultKubeconfig := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) 147 | if len(defaultKubeconfig) == 0 { 148 | defaultKubeconfig = clientcmd.RecommendedHomeFile 149 | } 150 | 151 | kubeconfig := flag.String(clientcmd.RecommendedConfigPathFlag, 152 | defaultKubeconfig, "absolute path to the kubeconfig file") 153 | 154 | namespace := flag.String("namespace", metav1.NamespaceAll, "create the deployment in this namespace") 155 | 156 | resyncIn := flag.Duration("resync", 0*time.Second, "resync period for the shared informer") 157 | 158 | flag.Parse() 159 | 160 | // build the config from the specified kubeconfig filepath 161 | cfg, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 162 | if err != nil { 163 | panic(err) 164 | } 165 | 166 | // creates the clientset 167 | clientset, err := kubernetes.NewForConfig(cfg) 168 | if err != nil { 169 | klog.Fatal(err) 170 | } 171 | 172 | // create the rate limiting work queue 173 | queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) 174 | 175 | // create a ListWatcher on PODs resources 176 | listWatcher := &cache.ListWatch{ 177 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 178 | // list Pods in the specified namespace 179 | return clientset.CoreV1().Pods(*namespace).List(context.Background(), options) 180 | }, 181 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 182 | return clientset.CoreV1().Pods(*namespace).Watch(context.Background(), options) 183 | }, 184 | } 185 | 186 | // create the shared informer and resync every `resyncIn` user defined value 187 | informer := cache.NewSharedInformer(listWatcher, &corev1.Pod{}, *resyncIn) 188 | 189 | // add the event handlers - that just simply enqueue items 190 | informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ 191 | AddFunc: func(obj interface{}) { 192 | key, err := cache.MetaNamespaceKeyFunc(obj) 193 | if err == nil { 194 | queue.Add(key) 195 | } 196 | }, 197 | UpdateFunc: func(old interface{}, new interface{}) { 198 | key, err := cache.MetaNamespaceKeyFunc(new) 199 | if err == nil { 200 | queue.Add(key) 201 | } 202 | }, 203 | DeleteFunc: func(obj interface{}) { 204 | // IndexerInformer uses a delta queue, therefore for 205 | // deletes we have to use this key function. 206 | key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) 207 | if err == nil { 208 | queue.Add(key) 209 | } 210 | }, 211 | }) 212 | 213 | // create the controller 214 | controller := NewController(queue, informer) 215 | 216 | // Now let's start the controller 217 | stop := make(chan struct{}) 218 | defer close(stop) 219 | go controller.Run(1, stop) 220 | 221 | // Wait forever 222 | select {} 223 | } 224 | -------------------------------------------------------------------------------- /using-codegen/pkg/generated/clientset/versioned/typed/expression/v1alpha1/expression.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | // Code generated by client-gen. DO NOT EDIT. 26 | 27 | package v1alpha1 28 | 29 | import ( 30 | "context" 31 | "time" 32 | 33 | v1alpha1 "github.com/lucasepe/using-client-go/using-codegen/pkg/apis/expression/v1alpha1" 34 | scheme "github.com/lucasepe/using-client-go/using-codegen/pkg/generated/clientset/versioned/scheme" 35 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 36 | types "k8s.io/apimachinery/pkg/types" 37 | watch "k8s.io/apimachinery/pkg/watch" 38 | rest "k8s.io/client-go/rest" 39 | ) 40 | 41 | // ExpressionsGetter has a method to return a ExpressionInterface. 42 | // A group's client should implement this interface. 43 | type ExpressionsGetter interface { 44 | Expressions(namespace string) ExpressionInterface 45 | } 46 | 47 | // ExpressionInterface has methods to work with Expression resources. 48 | type ExpressionInterface interface { 49 | Create(ctx context.Context, expression *v1alpha1.Expression, opts v1.CreateOptions) (*v1alpha1.Expression, error) 50 | Update(ctx context.Context, expression *v1alpha1.Expression, opts v1.UpdateOptions) (*v1alpha1.Expression, error) 51 | UpdateStatus(ctx context.Context, expression *v1alpha1.Expression, opts v1.UpdateOptions) (*v1alpha1.Expression, error) 52 | Delete(ctx context.Context, name string, opts v1.DeleteOptions) error 53 | DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error 54 | Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.Expression, error) 55 | List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.ExpressionList, error) 56 | Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) 57 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Expression, err error) 58 | ExpressionExpansion 59 | } 60 | 61 | // expressions implements ExpressionInterface 62 | type expressions struct { 63 | client rest.Interface 64 | ns string 65 | } 66 | 67 | // newExpressions returns a Expressions 68 | func newExpressions(c *ExampleV1alpha1Client, namespace string) *expressions { 69 | return &expressions{ 70 | client: c.RESTClient(), 71 | ns: namespace, 72 | } 73 | } 74 | 75 | // Get takes name of the expression, and returns the corresponding expression object, and an error if there is any. 76 | func (c *expressions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Expression, err error) { 77 | result = &v1alpha1.Expression{} 78 | err = c.client.Get(). 79 | Namespace(c.ns). 80 | Resource("expressions"). 81 | Name(name). 82 | VersionedParams(&options, scheme.ParameterCodec). 83 | Do(ctx). 84 | Into(result) 85 | return 86 | } 87 | 88 | // List takes label and field selectors, and returns the list of Expressions that match those selectors. 89 | func (c *expressions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ExpressionList, err error) { 90 | var timeout time.Duration 91 | if opts.TimeoutSeconds != nil { 92 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 93 | } 94 | result = &v1alpha1.ExpressionList{} 95 | err = c.client.Get(). 96 | Namespace(c.ns). 97 | Resource("expressions"). 98 | VersionedParams(&opts, scheme.ParameterCodec). 99 | Timeout(timeout). 100 | Do(ctx). 101 | Into(result) 102 | return 103 | } 104 | 105 | // Watch returns a watch.Interface that watches the requested expressions. 106 | func (c *expressions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { 107 | var timeout time.Duration 108 | if opts.TimeoutSeconds != nil { 109 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 110 | } 111 | opts.Watch = true 112 | return c.client.Get(). 113 | Namespace(c.ns). 114 | Resource("expressions"). 115 | VersionedParams(&opts, scheme.ParameterCodec). 116 | Timeout(timeout). 117 | Watch(ctx) 118 | } 119 | 120 | // Create takes the representation of a expression and creates it. Returns the server's representation of the expression, and an error, if there is any. 121 | func (c *expressions) Create(ctx context.Context, expression *v1alpha1.Expression, opts v1.CreateOptions) (result *v1alpha1.Expression, err error) { 122 | result = &v1alpha1.Expression{} 123 | err = c.client.Post(). 124 | Namespace(c.ns). 125 | Resource("expressions"). 126 | VersionedParams(&opts, scheme.ParameterCodec). 127 | Body(expression). 128 | Do(ctx). 129 | Into(result) 130 | return 131 | } 132 | 133 | // Update takes the representation of a expression and updates it. Returns the server's representation of the expression, and an error, if there is any. 134 | func (c *expressions) Update(ctx context.Context, expression *v1alpha1.Expression, opts v1.UpdateOptions) (result *v1alpha1.Expression, err error) { 135 | result = &v1alpha1.Expression{} 136 | err = c.client.Put(). 137 | Namespace(c.ns). 138 | Resource("expressions"). 139 | Name(expression.Name). 140 | VersionedParams(&opts, scheme.ParameterCodec). 141 | Body(expression). 142 | Do(ctx). 143 | Into(result) 144 | return 145 | } 146 | 147 | // UpdateStatus was generated because the type contains a Status member. 148 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 149 | func (c *expressions) UpdateStatus(ctx context.Context, expression *v1alpha1.Expression, opts v1.UpdateOptions) (result *v1alpha1.Expression, err error) { 150 | result = &v1alpha1.Expression{} 151 | err = c.client.Put(). 152 | Namespace(c.ns). 153 | Resource("expressions"). 154 | Name(expression.Name). 155 | SubResource("status"). 156 | VersionedParams(&opts, scheme.ParameterCodec). 157 | Body(expression). 158 | Do(ctx). 159 | Into(result) 160 | return 161 | } 162 | 163 | // Delete takes name of the expression and deletes it. Returns an error if one occurs. 164 | func (c *expressions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { 165 | return c.client.Delete(). 166 | Namespace(c.ns). 167 | Resource("expressions"). 168 | Name(name). 169 | Body(&opts). 170 | Do(ctx). 171 | Error() 172 | } 173 | 174 | // DeleteCollection deletes a collection of objects. 175 | func (c *expressions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { 176 | var timeout time.Duration 177 | if listOpts.TimeoutSeconds != nil { 178 | timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second 179 | } 180 | return c.client.Delete(). 181 | Namespace(c.ns). 182 | Resource("expressions"). 183 | VersionedParams(&listOpts, scheme.ParameterCodec). 184 | Timeout(timeout). 185 | Body(&opts). 186 | Do(ctx). 187 | Error() 188 | } 189 | 190 | // Patch applies the patch and returns the patched expression. 191 | func (c *expressions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Expression, err error) { 192 | result = &v1alpha1.Expression{} 193 | err = c.client.Patch(pt). 194 | Namespace(c.ns). 195 | Resource("expressions"). 196 | Name(name). 197 | SubResource(subresources...). 198 | VersionedParams(&opts, scheme.ParameterCodec). 199 | Body(data). 200 | Do(ctx). 201 | Into(result) 202 | return 203 | } 204 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 22 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 23 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 24 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 25 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 26 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 27 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 28 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 29 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 30 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 31 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 32 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 33 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 34 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 35 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 36 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 37 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 39 | github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= 40 | github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= 41 | github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= 42 | github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= 43 | github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= 44 | github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= 45 | github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 46 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 47 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 48 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 49 | github.com/PaesslerAG/gval v1.1.2 h1:EROKxV4/fAKWb0Qoj7NOxmHZA7gcpjOV9XgiRZMRCUU= 50 | github.com/PaesslerAG/gval v1.1.2/go.mod h1:Fa8gfkCmUsELXgayr8sfL/sw+VzCVoa03dcOcR/if2w= 51 | github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= 52 | github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= 53 | github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= 54 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 55 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= 56 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 57 | github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 58 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 59 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 60 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 61 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 62 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 63 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 64 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 65 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 66 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 67 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 68 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 69 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 70 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 71 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 72 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 73 | github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= 74 | github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 75 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 76 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 77 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 78 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 79 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 80 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 81 | github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= 82 | github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 83 | github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= 84 | github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= 85 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 86 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 87 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 88 | github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= 89 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 90 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 91 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 92 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 93 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 94 | github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= 95 | github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= 96 | github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 97 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 98 | github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= 99 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 100 | github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= 101 | github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= 102 | github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= 103 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 104 | github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= 105 | github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= 106 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 107 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 108 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 109 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 110 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 111 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 112 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 113 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 114 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 115 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 116 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 117 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 118 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 119 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 120 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 121 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 122 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 123 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 124 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 125 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 126 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 127 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 128 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 129 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 130 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 131 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 132 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 133 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 134 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 135 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 136 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 137 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 138 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 139 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 140 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 141 | github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= 142 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 143 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 144 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 145 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 146 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 147 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 148 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 149 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 150 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 151 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 152 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 153 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 154 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 155 | github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= 156 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 157 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 158 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 159 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 160 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 161 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 162 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 163 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 164 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 165 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 166 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 167 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 168 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 169 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 170 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 171 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 172 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 173 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 174 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 175 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 176 | github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= 177 | github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= 178 | github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= 179 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 180 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 181 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 182 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 183 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 184 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 185 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 186 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 187 | github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= 188 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 189 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 190 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 191 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 192 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 193 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 194 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 195 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 196 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 197 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 198 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 199 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 200 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 201 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 202 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 203 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 204 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 205 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 206 | github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= 207 | github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 208 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 209 | github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= 210 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 211 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 212 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 213 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 214 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 215 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 216 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 217 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 218 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 219 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 220 | github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= 221 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 222 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 223 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 224 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 225 | github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= 226 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 227 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 228 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 229 | github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= 230 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 231 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 232 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 233 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 234 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 235 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 236 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 237 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 238 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 239 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 240 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 241 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 242 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 243 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 244 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 245 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 246 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 247 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 248 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 249 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 250 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 251 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 252 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 253 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 254 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 255 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 256 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 257 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 258 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 259 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 260 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 261 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 262 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 263 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 264 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 265 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 266 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 267 | golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 268 | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 269 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 270 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 271 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 272 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 273 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 274 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 275 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 276 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 277 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 278 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 279 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 280 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 281 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 282 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 283 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 284 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 285 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 286 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 287 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 288 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 289 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 290 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 291 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 292 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 293 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 294 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 295 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 296 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 297 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 298 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 299 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 300 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 301 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 302 | golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= 303 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 304 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 305 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 306 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 307 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 308 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 309 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 310 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 311 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 312 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 313 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 314 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 315 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 316 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 317 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 318 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 319 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 320 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 321 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 322 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 323 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 324 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 325 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 326 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 327 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 328 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 329 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 330 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 331 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 332 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 333 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 334 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 335 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 336 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 337 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 338 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 339 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 340 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 341 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 342 | golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= 343 | golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 344 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 345 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 346 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 347 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 348 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 349 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 350 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 351 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 352 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 353 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 354 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 355 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= 356 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 357 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 358 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 359 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 360 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 361 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 362 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 363 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 364 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 365 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 366 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 367 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 368 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 369 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 370 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 371 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 372 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 373 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 374 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 375 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 376 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 377 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 378 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 379 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 380 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 381 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 382 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 383 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 384 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 385 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 386 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 387 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 388 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 389 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 390 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 391 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 392 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 393 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 394 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 395 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 396 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 397 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 398 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 399 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 400 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 401 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 402 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 403 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 404 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 405 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 406 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 407 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 408 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 409 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 410 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 411 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 412 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 413 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c= 414 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 415 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 416 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= 417 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 418 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 419 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 420 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 421 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 422 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 423 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 424 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 425 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 426 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 427 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 428 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 429 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 430 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 431 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= 432 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 433 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 434 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 435 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 436 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 437 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 438 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 439 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 440 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 441 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 442 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 443 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 444 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 445 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 446 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 447 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 448 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 449 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 450 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 451 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 452 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 453 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 454 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 455 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 456 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 457 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 458 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 459 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 460 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 461 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 462 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 463 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 464 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 465 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 466 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 467 | golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 468 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 469 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 470 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 471 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 472 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 473 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 474 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 475 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 476 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 477 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 478 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 479 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 480 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 481 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 482 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 483 | golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff h1:VX/uD7MK0AHXGiScH3fsieUQUcpmRERPDYtqZdJnA+Q= 484 | golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= 485 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 486 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 487 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 488 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 489 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 490 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 491 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 492 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 493 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 494 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 495 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 496 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 497 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 498 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 499 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 500 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 501 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 502 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 503 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 504 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 505 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 506 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 507 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 508 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 509 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 510 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 511 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 512 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 513 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 514 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 515 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 516 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 517 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 518 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 519 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 520 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 521 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 522 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 523 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 524 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 525 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 526 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 527 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 528 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 529 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 530 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 531 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 532 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 533 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 534 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 535 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 536 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 537 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 538 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 539 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 540 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 541 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 542 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 543 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 544 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 545 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 546 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 547 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 548 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 549 | google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 550 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 551 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 552 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 553 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 554 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 555 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 556 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 557 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 558 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 559 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 560 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 561 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 562 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 563 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 564 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 565 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 566 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 567 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 568 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 569 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 570 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 571 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 572 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 573 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 574 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 575 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 576 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 577 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 578 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 579 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 580 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 581 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 582 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 583 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 584 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 585 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 586 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 587 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 588 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 589 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 590 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 591 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 592 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 593 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 594 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 595 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 596 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 597 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 598 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 599 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 600 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 601 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 602 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 603 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 604 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 605 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 606 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 607 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 608 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 609 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 610 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 611 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 612 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 613 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 614 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 615 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 616 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 617 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 618 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 619 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 620 | k8s.io/api v0.23.3 h1:KNrME8KHGr12Ozjf8ytOewKzZh6hl/hHUZeHddT3a38= 621 | k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ= 622 | k8s.io/apimachinery v0.23.3 h1:7IW6jxNzrXTsP0c8yXz2E5Yx/WTzVPTsHIx/2Vm0cIk= 623 | k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= 624 | k8s.io/client-go v0.23.3 h1:23QYUmCQ/W6hW78xIwm3XqZrrKZM+LWDqW2zfo+szJs= 625 | k8s.io/client-go v0.23.3/go.mod h1:47oMd+YvAOqZM7pcQ6neJtBiFH7alOyfunYN48VsmwE= 626 | k8s.io/code-generator v0.23.5 h1:xn3a6J5pUL49AoH6SPrOFtnB5cvdMl76f/bEY176R3c= 627 | k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= 628 | k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA= 629 | k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= 630 | k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= 631 | k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= 632 | k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= 633 | k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= 634 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= 635 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= 636 | k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 637 | k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= 638 | k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 639 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 640 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 641 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 642 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= 643 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= 644 | sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= 645 | sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= 646 | sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= 647 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= 648 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 649 | --------------------------------------------------------------------------------