diff --git a/handler.go b/handler.go index da441abd..b2e07f57 100644 --- a/handler.go +++ b/handler.go @@ -199,14 +199,35 @@ func (resolver *OCPDNSNameResolver) updateResolvedNamesSuccess( go func(namespace string, objName string) { defer wg.Done() + previousResourceVersion := "0" // Retry the update of the DNSNameResolver object if there's a conflict during the update. retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Fetch the DNSNameResolver object. - resolverObj, err := ocpnetworkv1alpha1lister.NewDNSNameResolverLister( + var ( + resolverObj *ocpnetworkapiv1alpha1.DNSNameResolver + resourceVersion string + err error + ) + + // Fetch the DNSNameResolver object using the lister first. + resolverObj, err = ocpnetworkv1alpha1lister.NewDNSNameResolverLister( resolver.dnsNameResolverInformer.GetIndexer()).DNSNameResolvers(namespace).Get(objName) if err != nil { return err } + resourceVersion = resolverObj.GetResourceVersion() + // Check if the current and the previous resource version match or not. + if resourceVersion == previousResourceVersion { + listerResourceVersion := resourceVersion + // This indicates that there was a conflict and the lister has not caught up. + // So fetch the DNSNameResolver object using the client. + resolverObj, err = resolver.ocpNetworkClient.DNSNameResolvers(namespace).Get(ctx, objName, metav1.GetOptions{}) + if err != nil { + return err + } + resourceVersion = resolverObj.GetResourceVersion() + log.Infof("lister was stale at resourceVersion=%v, live get showed resourceVersion=%v", listerResourceVersion, resourceVersion) + } + previousResourceVersion = resourceVersion // Make a copy of the object. All the updates will be applied to the copied object. newResolverObj := resolverObj.DeepCopy() @@ -560,13 +581,34 @@ func (resolver *OCPDNSNameResolver) updateResolvedNamesFailure(ctx context.Conte go func(namespace string, objName string) { defer wg.Done() + previousResourceVersion := "0" // Retry the update of the DNSNameResolver object if there's a conflict during the update. retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Fetch the DNSNameResolver object. - resolverObj, err := ocpnetworkv1alpha1lister.NewDNSNameResolverLister(resolver.dnsNameResolverInformer.GetIndexer()).DNSNameResolvers(namespace).Get(objName) + var ( + resolverObj *ocpnetworkapiv1alpha1.DNSNameResolver + resourceVersion string + err error + ) + // Fetch the DNSNameResolver object using the lister first. + resolverObj, err = ocpnetworkv1alpha1lister.NewDNSNameResolverLister( + resolver.dnsNameResolverInformer.GetIndexer()).DNSNameResolvers(namespace).Get(objName) if err != nil { return err } + resourceVersion = resolverObj.GetResourceVersion() + // Check if the current and the previous resource version match or not. + if resourceVersion == previousResourceVersion { + listerResourceVersion := resourceVersion + // This indicates that there was a conflict and the lister has not caught up. + // So fetch the DNSNameResolver object using the client. + resolverObj, err = resolver.ocpNetworkClient.DNSNameResolvers(namespace).Get(ctx, objName, metav1.GetOptions{}) + if err != nil { + return err + } + resourceVersion = resolverObj.GetResourceVersion() + log.Infof("lister was stale at resourceVersion=%v, live get showed resourceVersion=%v", listerResourceVersion, resourceVersion) + } + previousResourceVersion = resourceVersion // Make a copy of the object. All the updates will be applied to the copied object. newResolverObj := resolverObj.DeepCopy() diff --git a/operator/controller/dnsnameresolver/resolver.go b/operator/controller/dnsnameresolver/resolver.go index 99eabf88..bb08623c 100644 --- a/operator/controller/dnsnameresolver/resolver.go +++ b/operator/controller/dnsnameresolver/resolver.go @@ -105,23 +105,29 @@ func (resolver *Resolver) Start() { nextDNSName, nextLookupTime, numIPs, exists = resolver.delete(deletedDNSDetails) } remainingDuration := time.Until(nextLookupTime) - if !exists || remainingDuration > defaultMaxTTL { - // If no DNS name is found OR If the remaining duration is greater than default maximum TTL, then perform DNS lookup - // after default maximum TTL. - timeTillNextLookup = defaultMaxTTL - } else if remainingDuration.Seconds() > 0 { - // If the remaining duration is positive and less than default maximum TTL, then perform DNS lookup - // after the remaining duration. - timeTillNextLookup = remainingDuration - } else { - // TTL of the DNS name has already expired, so send DNS lookup request as soon as possible. - timeTillNextLookup = 1 * time.Millisecond - } + timeTillNextLookup = getTimeTillNextLookup(exists, remainingDuration) timer.Reset(timeTillNextLookup) } }() } +// getTimeTillNextLookup returns the duration after which the next DNS lookup should be performed. +func getTimeTillNextLookup(exists bool, remainingDuration time.Duration) time.Duration { + if !exists || remainingDuration > defaultMaxTTL { + // If no DNS name is found OR If the remaining duration is greater than default maximum TTL, then perform DNS lookup + // after default maximum TTL. + return defaultMaxTTL + } else if remainingDuration.Seconds() > 0 { + // If the remaining duration is positive and less than default maximum TTL, then perform DNS lookup + // after the remaining duration. + return remainingDuration + } else { + // A DNS lookup request has been sent upon TTL expiration of the DNS name. Reset the timer to wait until twice of default + // minimum TTL to perform the next lookup. + return 2 * defaultMinTTL + } +} + // AddResolvedName is called whenever a DNSNameResolver object is added or updated. func (resolver *Resolver) AddResolvedName(dnsDetails dnsDetails) { // Send a signal to the added channel indicating that details corresponding to a DNS @@ -304,6 +310,12 @@ func (resolver *Resolver) getNextDNSNameDetails() (string, time.Time, int, bool) dns = dnsName numIPs = resolvedName.numIPs } + // If there are no IP addresses associated with the DNS name and the next lookup + // time of the DNS name is already past the current time, then reset the next + // lookup time to the default maximum TTL. + if resolvedName.numIPs == 0 && !time.Now().Before(resolvedName.minNextLookupTime) { + resolvedName.minNextLookupTime = time.Now().Add(defaultMaxTTL) + } } return dns, minNextLookupTime, numIPs, exists } diff --git a/operator/controller/dnsnameresolver/resolver_test.go b/operator/controller/dnsnameresolver/resolver_test.go index fb7b9fcc..4f25fa32 100644 --- a/operator/controller/dnsnameresolver/resolver_test.go +++ b/operator/controller/dnsnameresolver/resolver_test.go @@ -232,6 +232,34 @@ func TestResolver(t *testing.T) { expectedNumIPs: []int{2, 2, 2, 1}, expectedOutputs: []bool{true, true, true, true}, }, + { + name: "Add a regular DNS name first with an IP address and with next lookup time past the current time," + + " then add the same regular DNS name again without any resolved address", + actions: []string{"Add", "Add"}, + parameters: []interface{}{ + &addParams{ + dnsName: "www.example.com.", + resolvedAddresses: []networkv1alpha1.DNSNameResolverResolvedAddress{ + { + IP: "1.1.1.1", + TTLSeconds: -5, + LastLookupTime: &v1.Time{Time: time.Now()}, + }, + }, + matchesRegular: true, + objName: "regular", + }, + &addParams{ + dnsName: "www.example.com.", + matchesRegular: true, + objName: "regular", + }, + }, + expectedNextDNSNames: []string{"www.example.com.", "www.example.com."}, + expectedNextLookupTimes: []time.Time{time.Now().Add(-5 * time.Second), time.Now().Add(defaultMaxTTL)}, + expectedNumIPs: []int{1, 0}, + expectedOutputs: []bool{true, true}, + }, } for _, tc := range tests { @@ -278,3 +306,44 @@ func TestResolver(t *testing.T) { }) } } + +func TestGetTimeTillNextLookup(t *testing.T) { + tests := []struct { + name string + dnsExists bool + remainingDuration time.Duration + expectedTimeTillNextLookup time.Duration + }{ + { + name: "DNS does not exist", + dnsExists: false, + remainingDuration: 0, + expectedTimeTillNextLookup: defaultMaxTTL, + }, + { + name: "DNS exists and remaianing duration is greater than default max TTL", + dnsExists: true, + remainingDuration: defaultMaxTTL + 1, + expectedTimeTillNextLookup: defaultMaxTTL, + }, + { + name: "DNS exists and remaining duration is less than default max TTL", + dnsExists: true, + remainingDuration: defaultMinTTL, + expectedTimeTillNextLookup: defaultMinTTL, + }, + { + name: "DNS exists and remaining duration is not greater than 0", + dnsExists: true, + remainingDuration: 0, + expectedTimeTillNextLookup: 2 * defaultMinTTL, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + timeTillNextLookup := getTimeTillNextLookup(tc.dnsExists, tc.remainingDuration) + assert.Equal(t, tc.expectedTimeTillNextLookup, timeTillNextLookup) + }) + } +} diff --git a/operator/go.mod b/operator/go.mod index a7ef9141..9e9993ae 100644 --- a/operator/go.mod +++ b/operator/go.mod @@ -3,7 +3,6 @@ module github.com/openshift/coredns-ocp-dnsnameresolver/operator go 1.21 require ( - github.com/go-logr/logr v1.2.4 github.com/google/go-cmp v0.5.9 github.com/miekg/dns v1.1.58 github.com/onsi/ginkgo/v2 v2.13.0 @@ -22,9 +21,9 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.8.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect diff --git a/operator/go.sum b/operator/go.sum index b894917b..8258536b 100644 --- a/operator/go.sum +++ b/operator/go.sum @@ -63,6 +63,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -100,6 +101,7 @@ github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGy github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -119,6 +121,7 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -152,6 +155,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/operator/vendor/github.com/evanphx/json-patch/.gitignore b/operator/vendor/github.com/evanphx/json-patch/.gitignore deleted file mode 100644 index b7ed7f95..00000000 --- a/operator/vendor/github.com/evanphx/json-patch/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# editor and IDE paraphernalia -.idea -.vscode - -# macOS paraphernalia -.DS_Store diff --git a/operator/vendor/github.com/evanphx/json-patch/LICENSE b/operator/vendor/github.com/evanphx/json-patch/LICENSE deleted file mode 100644 index df76d7d7..00000000 --- a/operator/vendor/github.com/evanphx/json-patch/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2014, Evan Phoenix -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of the Evan Phoenix nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/operator/vendor/github.com/evanphx/json-patch/README.md b/operator/vendor/github.com/evanphx/json-patch/README.md deleted file mode 100644 index 28e35169..00000000 --- a/operator/vendor/github.com/evanphx/json-patch/README.md +++ /dev/null @@ -1,317 +0,0 @@ -# JSON-Patch -`jsonpatch` is a library which provides functionality for both applying -[RFC6902 JSON patches](http://tools.ietf.org/html/rfc6902) against documents, as -well as for calculating & applying [RFC7396 JSON merge patches](https://tools.ietf.org/html/rfc7396). - -[![GoDoc](https://godoc.org/github.com/evanphx/json-patch?status.svg)](http://godoc.org/github.com/evanphx/json-patch) -[![Build Status](https://travis-ci.org/evanphx/json-patch.svg?branch=master)](https://travis-ci.org/evanphx/json-patch) -[![Report Card](https://goreportcard.com/badge/github.com/evanphx/json-patch)](https://goreportcard.com/report/github.com/evanphx/json-patch) - -# Get It! - -**Latest and greatest**: -```bash -go get -u github.com/evanphx/json-patch/v5 -``` - -**Stable Versions**: -* Version 5: `go get -u gopkg.in/evanphx/json-patch.v5` -* Version 4: `go get -u gopkg.in/evanphx/json-patch.v4` - -(previous versions below `v3` are unavailable) - -# Use It! -* [Create and apply a merge patch](#create-and-apply-a-merge-patch) -* [Create and apply a JSON Patch](#create-and-apply-a-json-patch) -* [Comparing JSON documents](#comparing-json-documents) -* [Combine merge patches](#combine-merge-patches) - - -# Configuration - -* There is a global configuration variable `jsonpatch.SupportNegativeIndices`. - This defaults to `true` and enables the non-standard practice of allowing - negative indices to mean indices starting at the end of an array. This - functionality can be disabled by setting `jsonpatch.SupportNegativeIndices = - false`. - -* There is a global configuration variable `jsonpatch.AccumulatedCopySizeLimit`, - which limits the total size increase in bytes caused by "copy" operations in a - patch. It defaults to 0, which means there is no limit. - -These global variables control the behavior of `jsonpatch.Apply`. - -An alternative to `jsonpatch.Apply` is `jsonpatch.ApplyWithOptions` whose behavior -is controlled by an `options` parameter of type `*jsonpatch.ApplyOptions`. - -Structure `jsonpatch.ApplyOptions` includes the configuration options above -and adds two new options: `AllowMissingPathOnRemove` and `EnsurePathExistsOnAdd`. - -When `AllowMissingPathOnRemove` is set to `true`, `jsonpatch.ApplyWithOptions` will ignore -`remove` operations whose `path` points to a non-existent location in the JSON document. -`AllowMissingPathOnRemove` defaults to `false` which will lead to `jsonpatch.ApplyWithOptions` -returning an error when hitting a missing `path` on `remove`. - -When `EnsurePathExistsOnAdd` is set to `true`, `jsonpatch.ApplyWithOptions` will make sure -that `add` operations produce all the `path` elements that are missing from the target object. - -Use `jsonpatch.NewApplyOptions` to create an instance of `jsonpatch.ApplyOptions` -whose values are populated from the global configuration variables. - -## Create and apply a merge patch -Given both an original JSON document and a modified JSON document, you can create -a [Merge Patch](https://tools.ietf.org/html/rfc7396) document. - -It can describe the changes needed to convert from the original to the -modified JSON document. - -Once you have a merge patch, you can apply it to other JSON documents using the -`jsonpatch.MergePatch(document, patch)` function. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - // Let's create a merge patch from these two documents... - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - target := []byte(`{"name": "Jane", "age": 24}`) - - patch, err := jsonpatch.CreateMergePatch(original, target) - if err != nil { - panic(err) - } - - // Now lets apply the patch against a different JSON document... - - alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`) - modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch) - - fmt.Printf("patch document: %s\n", patch) - fmt.Printf("updated alternative doc: %s\n", modifiedAlternative) -} -``` - -When ran, you get the following output: - -```bash -$ go run main.go -patch document: {"height":null,"name":"Jane"} -updated alternative doc: {"age":28,"name":"Jane"} -``` - -## Create and apply a JSON Patch -You can create patch objects using `DecodePatch([]byte)`, which can then -be applied against JSON documents. - -The following is an example of creating a patch from two operations, and -applying it against a JSON document. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - patchJSON := []byte(`[ - {"op": "replace", "path": "/name", "value": "Jane"}, - {"op": "remove", "path": "/height"} - ]`) - - patch, err := jsonpatch.DecodePatch(patchJSON) - if err != nil { - panic(err) - } - - modified, err := patch.Apply(original) - if err != nil { - panic(err) - } - - fmt.Printf("Original document: %s\n", original) - fmt.Printf("Modified document: %s\n", modified) -} -``` - -When ran, you get the following output: - -```bash -$ go run main.go -Original document: {"name": "John", "age": 24, "height": 3.21} -Modified document: {"age":24,"name":"Jane"} -``` - -## Comparing JSON documents -Due to potential whitespace and ordering differences, one cannot simply compare -JSON strings or byte-arrays directly. - -As such, you can instead use `jsonpatch.Equal(document1, document2)` to -determine if two JSON documents are _structurally_ equal. This ignores -whitespace differences, and key-value ordering. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - similar := []byte(` - { - "age": 24, - "height": 3.21, - "name": "John" - } - `) - different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`) - - if jsonpatch.Equal(original, similar) { - fmt.Println(`"original" is structurally equal to "similar"`) - } - - if !jsonpatch.Equal(original, different) { - fmt.Println(`"original" is _not_ structurally equal to "different"`) - } -} -``` - -When ran, you get the following output: -```bash -$ go run main.go -"original" is structurally equal to "similar" -"original" is _not_ structurally equal to "different" -``` - -## Combine merge patches -Given two JSON merge patch documents, it is possible to combine them into a -single merge patch which can describe both set of changes. - -The resulting merge patch can be used such that applying it results in a -document structurally similar as merging each merge patch to the document -in succession. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - - nameAndHeight := []byte(`{"height":null,"name":"Jane"}`) - ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`) - - // Let's combine these merge patch documents... - combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes) - if err != nil { - panic(err) - } - - // Apply each patch individual against the original document - withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight) - if err != nil { - panic(err) - } - - withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes) - if err != nil { - panic(err) - } - - // Apply the combined patch against the original document - - withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch) - if err != nil { - panic(err) - } - - // Do both result in the same thing? They should! - if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) { - fmt.Println("Both JSON documents are structurally the same!") - } - - fmt.Printf("combined merge patch: %s", combinedPatch) -} -``` - -When ran, you get the following output: -```bash -$ go run main.go -Both JSON documents are structurally the same! -combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"} -``` - -# CLI for comparing JSON documents -You can install the commandline program `json-patch`. - -This program can take multiple JSON patch documents as arguments, -and fed a JSON document from `stdin`. It will apply the patch(es) against -the document and output the modified doc. - -**patch.1.json** -```json -[ - {"op": "replace", "path": "/name", "value": "Jane"}, - {"op": "remove", "path": "/height"} -] -``` - -**patch.2.json** -```json -[ - {"op": "add", "path": "/address", "value": "123 Main St"}, - {"op": "replace", "path": "/age", "value": "21"} -] -``` - -**document.json** -```json -{ - "name": "John", - "age": 24, - "height": 3.21 -} -``` - -You can then run: - -```bash -$ go install github.com/evanphx/json-patch/cmd/json-patch -$ cat document.json | json-patch -p patch.1.json -p patch.2.json -{"address":"123 Main St","age":"21","name":"Jane"} -``` - -# Help It! -Contributions are welcomed! Leave [an issue](https://github.com/evanphx/json-patch/issues) -or [create a PR](https://github.com/evanphx/json-patch/compare). - - -Before creating a pull request, we'd ask that you make sure tests are passing -and that you have added new tests when applicable. - -Contributors can run tests using: - -```bash -go test -cover ./... -``` - -Builds for pull requests are tested automatically -using [TravisCI](https://travis-ci.org/evanphx/json-patch). diff --git a/operator/vendor/github.com/evanphx/json-patch/errors.go b/operator/vendor/github.com/evanphx/json-patch/errors.go deleted file mode 100644 index 75304b44..00000000 --- a/operator/vendor/github.com/evanphx/json-patch/errors.go +++ /dev/null @@ -1,38 +0,0 @@ -package jsonpatch - -import "fmt" - -// AccumulatedCopySizeError is an error type returned when the accumulated size -// increase caused by copy operations in a patch operation has exceeded the -// limit. -type AccumulatedCopySizeError struct { - limit int64 - accumulated int64 -} - -// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError. -func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError { - return &AccumulatedCopySizeError{limit: l, accumulated: a} -} - -// Error implements the error interface. -func (a *AccumulatedCopySizeError) Error() string { - return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit) -} - -// ArraySizeError is an error type returned when the array size has exceeded -// the limit. -type ArraySizeError struct { - limit int - size int -} - -// NewArraySizeError returns an ArraySizeError. -func NewArraySizeError(l, s int) *ArraySizeError { - return &ArraySizeError{limit: l, size: s} -} - -// Error implements the error interface. -func (a *ArraySizeError) Error() string { - return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit) -} diff --git a/operator/vendor/github.com/evanphx/json-patch/merge.go b/operator/vendor/github.com/evanphx/json-patch/merge.go deleted file mode 100644 index ad88d401..00000000 --- a/operator/vendor/github.com/evanphx/json-patch/merge.go +++ /dev/null @@ -1,389 +0,0 @@ -package jsonpatch - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" -) - -func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode { - curDoc, err := cur.intoDoc() - - if err != nil { - pruneNulls(patch) - return patch - } - - patchDoc, err := patch.intoDoc() - - if err != nil { - return patch - } - - mergeDocs(curDoc, patchDoc, mergeMerge) - - return cur -} - -func mergeDocs(doc, patch *partialDoc, mergeMerge bool) { - for k, v := range *patch { - if v == nil { - if mergeMerge { - (*doc)[k] = nil - } else { - delete(*doc, k) - } - } else { - cur, ok := (*doc)[k] - - if !ok || cur == nil { - if !mergeMerge { - pruneNulls(v) - } - - (*doc)[k] = v - } else { - (*doc)[k] = merge(cur, v, mergeMerge) - } - } - } -} - -func pruneNulls(n *lazyNode) { - sub, err := n.intoDoc() - - if err == nil { - pruneDocNulls(sub) - } else { - ary, err := n.intoAry() - - if err == nil { - pruneAryNulls(ary) - } - } -} - -func pruneDocNulls(doc *partialDoc) *partialDoc { - for k, v := range *doc { - if v == nil { - delete(*doc, k) - } else { - pruneNulls(v) - } - } - - return doc -} - -func pruneAryNulls(ary *partialArray) *partialArray { - newAry := []*lazyNode{} - - for _, v := range *ary { - if v != nil { - pruneNulls(v) - } - newAry = append(newAry, v) - } - - *ary = newAry - - return ary -} - -var ErrBadJSONDoc = fmt.Errorf("Invalid JSON Document") -var ErrBadJSONPatch = fmt.Errorf("Invalid JSON Patch") -var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents") - -// MergeMergePatches merges two merge patches together, such that -// applying this resulting merged merge patch to a document yields the same -// as merging each merge patch to the document in succession. -func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) { - return doMergePatch(patch1Data, patch2Data, true) -} - -// MergePatch merges the patchData into the docData. -func MergePatch(docData, patchData []byte) ([]byte, error) { - return doMergePatch(docData, patchData, false) -} - -func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) { - doc := &partialDoc{} - - docErr := json.Unmarshal(docData, doc) - - patch := &partialDoc{} - - patchErr := json.Unmarshal(patchData, patch) - - if _, ok := docErr.(*json.SyntaxError); ok { - return nil, ErrBadJSONDoc - } - - if _, ok := patchErr.(*json.SyntaxError); ok { - return nil, ErrBadJSONPatch - } - - if docErr == nil && *doc == nil { - return nil, ErrBadJSONDoc - } - - if patchErr == nil && *patch == nil { - return nil, ErrBadJSONPatch - } - - if docErr != nil || patchErr != nil { - // Not an error, just not a doc, so we turn straight into the patch - if patchErr == nil { - if mergeMerge { - doc = patch - } else { - doc = pruneDocNulls(patch) - } - } else { - patchAry := &partialArray{} - patchErr = json.Unmarshal(patchData, patchAry) - - if patchErr != nil { - return nil, ErrBadJSONPatch - } - - pruneAryNulls(patchAry) - - out, patchErr := json.Marshal(patchAry) - - if patchErr != nil { - return nil, ErrBadJSONPatch - } - - return out, nil - } - } else { - mergeDocs(doc, patch, mergeMerge) - } - - return json.Marshal(doc) -} - -// resemblesJSONArray indicates whether the byte-slice "appears" to be -// a JSON array or not. -// False-positives are possible, as this function does not check the internal -// structure of the array. It only checks that the outer syntax is present and -// correct. -func resemblesJSONArray(input []byte) bool { - input = bytes.TrimSpace(input) - - hasPrefix := bytes.HasPrefix(input, []byte("[")) - hasSuffix := bytes.HasSuffix(input, []byte("]")) - - return hasPrefix && hasSuffix -} - -// CreateMergePatch will return a merge patch document capable of converting -// the original document(s) to the modified document(s). -// The parameters can be bytes of either two JSON Documents, or two arrays of -// JSON documents. -// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07 -func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalResemblesArray := resemblesJSONArray(originalJSON) - modifiedResemblesArray := resemblesJSONArray(modifiedJSON) - - // Do both byte-slices seem like JSON arrays? - if originalResemblesArray && modifiedResemblesArray { - return createArrayMergePatch(originalJSON, modifiedJSON) - } - - // Are both byte-slices are not arrays? Then they are likely JSON objects... - if !originalResemblesArray && !modifiedResemblesArray { - return createObjectMergePatch(originalJSON, modifiedJSON) - } - - // None of the above? Then return an error because of mismatched types. - return nil, errBadMergeTypes -} - -// createObjectMergePatch will return a merge-patch document capable of -// converting the original document to the modified document. -func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalDoc := map[string]interface{}{} - modifiedDoc := map[string]interface{}{} - - err := json.Unmarshal(originalJSON, &originalDoc) - if err != nil { - return nil, ErrBadJSONDoc - } - - err = json.Unmarshal(modifiedJSON, &modifiedDoc) - if err != nil { - return nil, ErrBadJSONDoc - } - - dest, err := getDiff(originalDoc, modifiedDoc) - if err != nil { - return nil, err - } - - return json.Marshal(dest) -} - -// createArrayMergePatch will return an array of merge-patch documents capable -// of converting the original document to the modified document for each -// pair of JSON documents provided in the arrays. -// Arrays of mismatched sizes will result in an error. -func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalDocs := []json.RawMessage{} - modifiedDocs := []json.RawMessage{} - - err := json.Unmarshal(originalJSON, &originalDocs) - if err != nil { - return nil, ErrBadJSONDoc - } - - err = json.Unmarshal(modifiedJSON, &modifiedDocs) - if err != nil { - return nil, ErrBadJSONDoc - } - - total := len(originalDocs) - if len(modifiedDocs) != total { - return nil, ErrBadJSONDoc - } - - result := []json.RawMessage{} - for i := 0; i < len(originalDocs); i++ { - original := originalDocs[i] - modified := modifiedDocs[i] - - patch, err := createObjectMergePatch(original, modified) - if err != nil { - return nil, err - } - - result = append(result, json.RawMessage(patch)) - } - - return json.Marshal(result) -} - -// Returns true if the array matches (must be json types). -// As is idiomatic for go, an empty array is not the same as a nil array. -func matchesArray(a, b []interface{}) bool { - if len(a) != len(b) { - return false - } - if (a == nil && b != nil) || (a != nil && b == nil) { - return false - } - for i := range a { - if !matchesValue(a[i], b[i]) { - return false - } - } - return true -} - -// Returns true if the values matches (must be json types) -// The types of the values must match, otherwise it will always return false -// If two map[string]interface{} are given, all elements must match. -func matchesValue(av, bv interface{}) bool { - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - return false - } - switch at := av.(type) { - case string: - bt := bv.(string) - if bt == at { - return true - } - case float64: - bt := bv.(float64) - if bt == at { - return true - } - case bool: - bt := bv.(bool) - if bt == at { - return true - } - case nil: - // Both nil, fine. - return true - case map[string]interface{}: - bt := bv.(map[string]interface{}) - if len(bt) != len(at) { - return false - } - for key := range bt { - av, aOK := at[key] - bv, bOK := bt[key] - if aOK != bOK { - return false - } - if !matchesValue(av, bv) { - return false - } - } - return true - case []interface{}: - bt := bv.([]interface{}) - return matchesArray(at, bt) - } - return false -} - -// getDiff returns the (recursive) difference between a and b as a map[string]interface{}. -func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { - into := map[string]interface{}{} - for key, bv := range b { - av, ok := a[key] - // value was added - if !ok { - into[key] = bv - continue - } - // If types have changed, replace completely - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - into[key] = bv - continue - } - // Types are the same, compare values - switch at := av.(type) { - case map[string]interface{}: - bt := bv.(map[string]interface{}) - dst := make(map[string]interface{}, len(bt)) - dst, err := getDiff(at, bt) - if err != nil { - return nil, err - } - if len(dst) > 0 { - into[key] = dst - } - case string, float64, bool: - if !matchesValue(av, bv) { - into[key] = bv - } - case []interface{}: - bt := bv.([]interface{}) - if !matchesArray(at, bt) { - into[key] = bv - } - case nil: - switch bv.(type) { - case nil: - // Both nil, fine. - default: - into[key] = bv - } - default: - panic(fmt.Sprintf("Unknown type:%T in key %s", av, key)) - } - } - // Now add all deleted values as nil - for key := range a { - _, found := b[key] - if !found { - into[key] = nil - } - } - return into, nil -} diff --git a/operator/vendor/github.com/evanphx/json-patch/patch.go b/operator/vendor/github.com/evanphx/json-patch/patch.go deleted file mode 100644 index 4bce5936..00000000 --- a/operator/vendor/github.com/evanphx/json-patch/patch.go +++ /dev/null @@ -1,809 +0,0 @@ -package jsonpatch - -import ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -const ( - eRaw = iota - eDoc - eAry -) - -var ( - // SupportNegativeIndices decides whether to support non-standard practice of - // allowing negative indices to mean indices starting at the end of an array. - // Default to true. - SupportNegativeIndices bool = true - // AccumulatedCopySizeLimit limits the total size increase in bytes caused by - // "copy" operations in a patch. - AccumulatedCopySizeLimit int64 = 0 -) - -var ( - ErrTestFailed = errors.New("test failed") - ErrMissing = errors.New("missing value") - ErrUnknownType = errors.New("unknown object type") - ErrInvalid = errors.New("invalid state detected") - ErrInvalidIndex = errors.New("invalid index referenced") -) - -type lazyNode struct { - raw *json.RawMessage - doc partialDoc - ary partialArray - which int -} - -// Operation is a single JSON-Patch step, such as a single 'add' operation. -type Operation map[string]*json.RawMessage - -// Patch is an ordered collection of Operations. -type Patch []Operation - -type partialDoc map[string]*lazyNode -type partialArray []*lazyNode - -type container interface { - get(key string) (*lazyNode, error) - set(key string, val *lazyNode) error - add(key string, val *lazyNode) error - remove(key string) error -} - -func newLazyNode(raw *json.RawMessage) *lazyNode { - return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw} -} - -func (n *lazyNode) MarshalJSON() ([]byte, error) { - switch n.which { - case eRaw: - return json.Marshal(n.raw) - case eDoc: - return json.Marshal(n.doc) - case eAry: - return json.Marshal(n.ary) - default: - return nil, ErrUnknownType - } -} - -func (n *lazyNode) UnmarshalJSON(data []byte) error { - dest := make(json.RawMessage, len(data)) - copy(dest, data) - n.raw = &dest - n.which = eRaw - return nil -} - -func deepCopy(src *lazyNode) (*lazyNode, int, error) { - if src == nil { - return nil, 0, nil - } - a, err := src.MarshalJSON() - if err != nil { - return nil, 0, err - } - sz := len(a) - ra := make(json.RawMessage, sz) - copy(ra, a) - return newLazyNode(&ra), sz, nil -} - -func (n *lazyNode) intoDoc() (*partialDoc, error) { - if n.which == eDoc { - return &n.doc, nil - } - - if n.raw == nil { - return nil, ErrInvalid - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return nil, err - } - - n.which = eDoc - return &n.doc, nil -} - -func (n *lazyNode) intoAry() (*partialArray, error) { - if n.which == eAry { - return &n.ary, nil - } - - if n.raw == nil { - return nil, ErrInvalid - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return nil, err - } - - n.which = eAry - return &n.ary, nil -} - -func (n *lazyNode) compact() []byte { - buf := &bytes.Buffer{} - - if n.raw == nil { - return nil - } - - err := json.Compact(buf, *n.raw) - - if err != nil { - return *n.raw - } - - return buf.Bytes() -} - -func (n *lazyNode) tryDoc() bool { - if n.raw == nil { - return false - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return false - } - - n.which = eDoc - return true -} - -func (n *lazyNode) tryAry() bool { - if n.raw == nil { - return false - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return false - } - - n.which = eAry - return true -} - -func (n *lazyNode) equal(o *lazyNode) bool { - if n.which == eRaw { - if !n.tryDoc() && !n.tryAry() { - if o.which != eRaw { - return false - } - - return bytes.Equal(n.compact(), o.compact()) - } - } - - if n.which == eDoc { - if o.which == eRaw { - if !o.tryDoc() { - return false - } - } - - if o.which != eDoc { - return false - } - - if len(n.doc) != len(o.doc) { - return false - } - - for k, v := range n.doc { - ov, ok := o.doc[k] - - if !ok { - return false - } - - if (v == nil) != (ov == nil) { - return false - } - - if v == nil && ov == nil { - continue - } - - if !v.equal(ov) { - return false - } - } - - return true - } - - if o.which != eAry && !o.tryAry() { - return false - } - - if len(n.ary) != len(o.ary) { - return false - } - - for idx, val := range n.ary { - if !val.equal(o.ary[idx]) { - return false - } - } - - return true -} - -// Kind reads the "op" field of the Operation. -func (o Operation) Kind() string { - if obj, ok := o["op"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown" - } - - return op - } - - return "unknown" -} - -// Path reads the "path" field of the Operation. -func (o Operation) Path() (string, error) { - if obj, ok := o["path"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown", err - } - - return op, nil - } - - return "unknown", errors.Wrapf(ErrMissing, "operation missing path field") -} - -// From reads the "from" field of the Operation. -func (o Operation) From() (string, error) { - if obj, ok := o["from"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown", err - } - - return op, nil - } - - return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field") -} - -func (o Operation) value() *lazyNode { - if obj, ok := o["value"]; ok { - return newLazyNode(obj) - } - - return nil -} - -// ValueInterface decodes the operation value into an interface. -func (o Operation) ValueInterface() (interface{}, error) { - if obj, ok := o["value"]; ok && obj != nil { - var v interface{} - - err := json.Unmarshal(*obj, &v) - - if err != nil { - return nil, err - } - - return v, nil - } - - return nil, errors.Wrapf(ErrMissing, "operation, missing value field") -} - -func isArray(buf []byte) bool { -Loop: - for _, c := range buf { - switch c { - case ' ': - case '\n': - case '\t': - continue - case '[': - return true - default: - break Loop - } - } - - return false -} - -func findObject(pd *container, path string) (container, string) { - doc := *pd - - split := strings.Split(path, "/") - - if len(split) < 2 { - return nil, "" - } - - parts := split[1 : len(split)-1] - - key := split[len(split)-1] - - var err error - - for _, part := range parts { - - next, ok := doc.get(decodePatchKey(part)) - - if next == nil || ok != nil { - return nil, "" - } - - if isArray(*next.raw) { - doc, err = next.intoAry() - - if err != nil { - return nil, "" - } - } else { - doc, err = next.intoDoc() - - if err != nil { - return nil, "" - } - } - } - - return doc, decodePatchKey(key) -} - -func (d *partialDoc) set(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) add(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) get(key string) (*lazyNode, error) { - return (*d)[key], nil -} - -func (d *partialDoc) remove(key string) error { - _, ok := (*d)[key] - if !ok { - return errors.Wrapf(ErrMissing, "Unable to remove nonexistent key: %s", key) - } - - delete(*d, key) - return nil -} - -// set should only be used to implement the "replace" operation, so "key" must -// be an already existing index in "d". -func (d *partialArray) set(key string, val *lazyNode) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(*d) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(*d) - } - - (*d)[idx] = val - return nil -} - -func (d *partialArray) add(key string, val *lazyNode) error { - if key == "-" { - *d = append(*d, val) - return nil - } - - idx, err := strconv.Atoi(key) - if err != nil { - return errors.Wrapf(err, "value was not a proper array index: '%s'", key) - } - - sz := len(*d) + 1 - - ary := make([]*lazyNode, sz) - - cur := *d - - if idx >= len(ary) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(ary) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(ary) - } - - copy(ary[0:idx], cur[0:idx]) - ary[idx] = val - copy(ary[idx+1:], cur[idx:]) - - *d = ary - return nil -} - -func (d *partialArray) get(key string) (*lazyNode, error) { - idx, err := strconv.Atoi(key) - - if err != nil { - return nil, err - } - - if idx < 0 { - if !SupportNegativeIndices { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(*d) { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(*d) - } - - if idx >= len(*d) { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - return (*d)[idx], nil -} - -func (d *partialArray) remove(key string) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - cur := *d - - if idx >= len(cur) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(cur) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(cur) - } - - ary := make([]*lazyNode, len(cur)-1) - - copy(ary[0:idx], cur[0:idx]) - copy(ary[idx:], cur[idx+1:]) - - *d = ary - return nil - -} - -func (p Patch) add(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "add operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path) - } - - err = con.add(key, op.value()) - if err != nil { - return errors.Wrapf(err, "error in add for path: '%s'", path) - } - - return nil -} - -func (p Patch) remove(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "remove operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path) - } - - err = con.remove(key) - if err != nil { - return errors.Wrapf(err, "error in remove for path: '%s'", path) - } - - return nil -} - -func (p Patch) replace(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "replace operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path) - } - - _, ok := con.get(key) - if ok != nil { - return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path) - } - - err = con.set(key, op.value()) - if err != nil { - return errors.Wrapf(err, "error in remove for path: '%s'", path) - } - - return nil -} - -func (p Patch) move(doc *container, op Operation) error { - from, err := op.From() - if err != nil { - return errors.Wrapf(err, "move operation failed to decode from") - } - - con, key := findObject(doc, from) - - if con == nil { - return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", key) - } - - err = con.remove(key) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", key) - } - - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "move operation failed to decode path") - } - - con, key = findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path) - } - - err = con.add(key, val) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", path) - } - - return nil -} - -func (p Patch) test(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "test operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in test for path: '%s'", path) - } - - if val == nil { - if op.value().raw == nil { - return nil - } - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } else if op.value() == nil { - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } - - if val.equal(op.value()) { - return nil - } - - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) -} - -func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error { - from, err := op.From() - if err != nil { - return errors.Wrapf(err, "copy operation failed to decode from") - } - - con, key := findObject(doc, from) - - if con == nil { - return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in copy for from: '%s'", from) - } - - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "copy operation failed to decode path") - } - - con, key = findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path) - } - - valCopy, sz, err := deepCopy(val) - if err != nil { - return errors.Wrapf(err, "error while performing deep copy") - } - - (*accumulatedCopySize) += int64(sz) - if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit { - return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize) - } - - err = con.add(key, valCopy) - if err != nil { - return errors.Wrapf(err, "error while adding value during copy") - } - - return nil -} - -// Equal indicates if 2 JSON documents have the same structural equality. -func Equal(a, b []byte) bool { - ra := make(json.RawMessage, len(a)) - copy(ra, a) - la := newLazyNode(&ra) - - rb := make(json.RawMessage, len(b)) - copy(rb, b) - lb := newLazyNode(&rb) - - return la.equal(lb) -} - -// DecodePatch decodes the passed JSON document as an RFC 6902 patch. -func DecodePatch(buf []byte) (Patch, error) { - var p Patch - - err := json.Unmarshal(buf, &p) - - if err != nil { - return nil, err - } - - return p, nil -} - -// Apply mutates a JSON document according to the patch, and returns the new -// document. -func (p Patch) Apply(doc []byte) ([]byte, error) { - return p.ApplyIndent(doc, "") -} - -// ApplyIndent mutates a JSON document according to the patch, and returns the new -// document indented. -func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { - if len(doc) == 0 { - return doc, nil - } - - var pd container - if doc[0] == '[' { - pd = &partialArray{} - } else { - pd = &partialDoc{} - } - - err := json.Unmarshal(doc, pd) - - if err != nil { - return nil, err - } - - err = nil - - var accumulatedCopySize int64 - - for _, op := range p { - switch op.Kind() { - case "add": - err = p.add(&pd, op) - case "remove": - err = p.remove(&pd, op) - case "replace": - err = p.replace(&pd, op) - case "move": - err = p.move(&pd, op) - case "test": - err = p.test(&pd, op) - case "copy": - err = p.copy(&pd, op, &accumulatedCopySize) - default: - err = fmt.Errorf("Unexpected kind: %s", op.Kind()) - } - - if err != nil { - return nil, err - } - } - - if indent != "" { - return json.MarshalIndent(pd, "", indent) - } - - return json.Marshal(pd) -} - -// From http://tools.ietf.org/html/rfc6901#section-4 : -// -// Evaluation of each reference token begins by decoding any escaped -// character sequence. This is performed by first transforming any -// occurrence of the sequence '~1' to '/', and then transforming any -// occurrence of the sequence '~0' to '~'. - -var ( - rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~") -) - -func decodePatchKey(k string) string { - return rfc6901Decoder.Replace(k) -} diff --git a/operator/vendor/k8s.io/apimachinery/pkg/util/rand/rand.go b/operator/vendor/k8s.io/apimachinery/pkg/util/rand/rand.go deleted file mode 100644 index 82a473bb..00000000 --- a/operator/vendor/k8s.io/apimachinery/pkg/util/rand/rand.go +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package rand provides utilities related to randomization. -package rand - -import ( - "math/rand" - "sync" - "time" -) - -var rng = struct { - sync.Mutex - rand *rand.Rand -}{ - rand: rand.New(rand.NewSource(time.Now().UnixNano())), -} - -// Int returns a non-negative pseudo-random int. -func Int() int { - rng.Lock() - defer rng.Unlock() - return rng.rand.Int() -} - -// Intn generates an integer in range [0,max). -// By design this should panic if input is invalid, <= 0. -func Intn(max int) int { - rng.Lock() - defer rng.Unlock() - return rng.rand.Intn(max) -} - -// IntnRange generates an integer in range [min,max). -// By design this should panic if input is invalid, <= 0. -func IntnRange(min, max int) int { - rng.Lock() - defer rng.Unlock() - return rng.rand.Intn(max-min) + min -} - -// IntnRange generates an int64 integer in range [min,max). -// By design this should panic if input is invalid, <= 0. -func Int63nRange(min, max int64) int64 { - rng.Lock() - defer rng.Unlock() - return rng.rand.Int63n(max-min) + min -} - -// Seed seeds the rng with the provided seed. -func Seed(seed int64) { - rng.Lock() - defer rng.Unlock() - - rng.rand = rand.New(rand.NewSource(seed)) -} - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n) -// from the default Source. -func Perm(n int) []int { - rng.Lock() - defer rng.Unlock() - return rng.rand.Perm(n) -} - -const ( - // We omit vowels from the set of available characters to reduce the chances - // of "bad words" being formed. - alphanums = "bcdfghjklmnpqrstvwxz2456789" - // No. of bits required to index into alphanums string. - alphanumsIdxBits = 5 - // Mask used to extract last alphanumsIdxBits of an int. - alphanumsIdxMask = 1<>= alphanumsIdxBits - remaining-- - } - return string(b) -} - -// SafeEncodeString encodes s using the same characters as rand.String. This reduces the chances of bad words and -// ensures that strings generated from hash functions appear consistent throughout the API. -func SafeEncodeString(s string) string { - r := make([]byte, len(s)) - for i, b := range []rune(s) { - r[i] = alphanums[(int(b) % len(alphanums))] - } - return string(r) -} diff --git a/operator/vendor/k8s.io/client-go/testing/actions.go b/operator/vendor/k8s.io/client-go/testing/actions.go deleted file mode 100644 index c8ae0aaf..00000000 --- a/operator/vendor/k8s.io/client-go/testing/actions.go +++ /dev/null @@ -1,698 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package testing - -import ( - "fmt" - "path" - "strings" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" -) - -func NewRootGetAction(resource schema.GroupVersionResource, name string) GetActionImpl { - action := GetActionImpl{} - action.Verb = "get" - action.Resource = resource - action.Name = name - - return action -} - -func NewGetAction(resource schema.GroupVersionResource, namespace, name string) GetActionImpl { - action := GetActionImpl{} - action.Verb = "get" - action.Resource = resource - action.Namespace = namespace - action.Name = name - - return action -} - -func NewGetSubresourceAction(resource schema.GroupVersionResource, namespace, subresource, name string) GetActionImpl { - action := GetActionImpl{} - action.Verb = "get" - action.Resource = resource - action.Subresource = subresource - action.Namespace = namespace - action.Name = name - - return action -} - -func NewRootGetSubresourceAction(resource schema.GroupVersionResource, subresource, name string) GetActionImpl { - action := GetActionImpl{} - action.Verb = "get" - action.Resource = resource - action.Subresource = subresource - action.Name = name - - return action -} - -func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl { - action := ListActionImpl{} - action.Verb = "list" - action.Resource = resource - action.Kind = kind - labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) - action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} - - return action -} - -func NewListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, namespace string, opts interface{}) ListActionImpl { - action := ListActionImpl{} - action.Verb = "list" - action.Resource = resource - action.Kind = kind - action.Namespace = namespace - labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) - action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} - - return action -} - -func NewRootCreateAction(resource schema.GroupVersionResource, object runtime.Object) CreateActionImpl { - action := CreateActionImpl{} - action.Verb = "create" - action.Resource = resource - action.Object = object - - return action -} - -func NewCreateAction(resource schema.GroupVersionResource, namespace string, object runtime.Object) CreateActionImpl { - action := CreateActionImpl{} - action.Verb = "create" - action.Resource = resource - action.Namespace = namespace - action.Object = object - - return action -} - -func NewRootCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource string, object runtime.Object) CreateActionImpl { - action := CreateActionImpl{} - action.Verb = "create" - action.Resource = resource - action.Subresource = subresource - action.Name = name - action.Object = object - - return action -} - -func NewCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource, namespace string, object runtime.Object) CreateActionImpl { - action := CreateActionImpl{} - action.Verb = "create" - action.Resource = resource - action.Namespace = namespace - action.Subresource = subresource - action.Name = name - action.Object = object - - return action -} - -func NewRootUpdateAction(resource schema.GroupVersionResource, object runtime.Object) UpdateActionImpl { - action := UpdateActionImpl{} - action.Verb = "update" - action.Resource = resource - action.Object = object - - return action -} - -func NewUpdateAction(resource schema.GroupVersionResource, namespace string, object runtime.Object) UpdateActionImpl { - action := UpdateActionImpl{} - action.Verb = "update" - action.Resource = resource - action.Namespace = namespace - action.Object = object - - return action -} - -func NewRootPatchAction(resource schema.GroupVersionResource, name string, pt types.PatchType, patch []byte) PatchActionImpl { - action := PatchActionImpl{} - action.Verb = "patch" - action.Resource = resource - action.Name = name - action.PatchType = pt - action.Patch = patch - - return action -} - -func NewPatchAction(resource schema.GroupVersionResource, namespace string, name string, pt types.PatchType, patch []byte) PatchActionImpl { - action := PatchActionImpl{} - action.Verb = "patch" - action.Resource = resource - action.Namespace = namespace - action.Name = name - action.PatchType = pt - action.Patch = patch - - return action -} - -func NewRootPatchSubresourceAction(resource schema.GroupVersionResource, name string, pt types.PatchType, patch []byte, subresources ...string) PatchActionImpl { - action := PatchActionImpl{} - action.Verb = "patch" - action.Resource = resource - action.Subresource = path.Join(subresources...) - action.Name = name - action.PatchType = pt - action.Patch = patch - - return action -} - -func NewPatchSubresourceAction(resource schema.GroupVersionResource, namespace, name string, pt types.PatchType, patch []byte, subresources ...string) PatchActionImpl { - action := PatchActionImpl{} - action.Verb = "patch" - action.Resource = resource - action.Subresource = path.Join(subresources...) - action.Namespace = namespace - action.Name = name - action.PatchType = pt - action.Patch = patch - - return action -} - -func NewRootUpdateSubresourceAction(resource schema.GroupVersionResource, subresource string, object runtime.Object) UpdateActionImpl { - action := UpdateActionImpl{} - action.Verb = "update" - action.Resource = resource - action.Subresource = subresource - action.Object = object - - return action -} -func NewUpdateSubresourceAction(resource schema.GroupVersionResource, subresource string, namespace string, object runtime.Object) UpdateActionImpl { - action := UpdateActionImpl{} - action.Verb = "update" - action.Resource = resource - action.Subresource = subresource - action.Namespace = namespace - action.Object = object - - return action -} - -func NewRootDeleteAction(resource schema.GroupVersionResource, name string) DeleteActionImpl { - return NewRootDeleteActionWithOptions(resource, name, metav1.DeleteOptions{}) -} - -func NewRootDeleteActionWithOptions(resource schema.GroupVersionResource, name string, opts metav1.DeleteOptions) DeleteActionImpl { - action := DeleteActionImpl{} - action.Verb = "delete" - action.Resource = resource - action.Name = name - action.DeleteOptions = opts - - return action -} - -func NewRootDeleteSubresourceAction(resource schema.GroupVersionResource, subresource string, name string) DeleteActionImpl { - action := DeleteActionImpl{} - action.Verb = "delete" - action.Resource = resource - action.Subresource = subresource - action.Name = name - - return action -} - -func NewDeleteAction(resource schema.GroupVersionResource, namespace, name string) DeleteActionImpl { - return NewDeleteActionWithOptions(resource, namespace, name, metav1.DeleteOptions{}) -} - -func NewDeleteActionWithOptions(resource schema.GroupVersionResource, namespace, name string, opts metav1.DeleteOptions) DeleteActionImpl { - action := DeleteActionImpl{} - action.Verb = "delete" - action.Resource = resource - action.Namespace = namespace - action.Name = name - action.DeleteOptions = opts - - return action -} - -func NewDeleteSubresourceAction(resource schema.GroupVersionResource, subresource, namespace, name string) DeleteActionImpl { - action := DeleteActionImpl{} - action.Verb = "delete" - action.Resource = resource - action.Subresource = subresource - action.Namespace = namespace - action.Name = name - - return action -} - -func NewRootDeleteCollectionAction(resource schema.GroupVersionResource, opts interface{}) DeleteCollectionActionImpl { - action := DeleteCollectionActionImpl{} - action.Verb = "delete-collection" - action.Resource = resource - labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) - action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} - - return action -} - -func NewDeleteCollectionAction(resource schema.GroupVersionResource, namespace string, opts interface{}) DeleteCollectionActionImpl { - action := DeleteCollectionActionImpl{} - action.Verb = "delete-collection" - action.Resource = resource - action.Namespace = namespace - labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) - action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} - - return action -} - -func NewRootWatchAction(resource schema.GroupVersionResource, opts interface{}) WatchActionImpl { - action := WatchActionImpl{} - action.Verb = "watch" - action.Resource = resource - labelSelector, fieldSelector, resourceVersion := ExtractFromListOptions(opts) - action.WatchRestrictions = WatchRestrictions{labelSelector, fieldSelector, resourceVersion} - - return action -} - -func ExtractFromListOptions(opts interface{}) (labelSelector labels.Selector, fieldSelector fields.Selector, resourceVersion string) { - var err error - switch t := opts.(type) { - case metav1.ListOptions: - labelSelector, err = labels.Parse(t.LabelSelector) - if err != nil { - panic(fmt.Errorf("invalid selector %q: %v", t.LabelSelector, err)) - } - fieldSelector, err = fields.ParseSelector(t.FieldSelector) - if err != nil { - panic(fmt.Errorf("invalid selector %q: %v", t.FieldSelector, err)) - } - resourceVersion = t.ResourceVersion - default: - panic(fmt.Errorf("expect a ListOptions %T", opts)) - } - if labelSelector == nil { - labelSelector = labels.Everything() - } - if fieldSelector == nil { - fieldSelector = fields.Everything() - } - return labelSelector, fieldSelector, resourceVersion -} - -func NewWatchAction(resource schema.GroupVersionResource, namespace string, opts interface{}) WatchActionImpl { - action := WatchActionImpl{} - action.Verb = "watch" - action.Resource = resource - action.Namespace = namespace - labelSelector, fieldSelector, resourceVersion := ExtractFromListOptions(opts) - action.WatchRestrictions = WatchRestrictions{labelSelector, fieldSelector, resourceVersion} - - return action -} - -func NewProxyGetAction(resource schema.GroupVersionResource, namespace, scheme, name, port, path string, params map[string]string) ProxyGetActionImpl { - action := ProxyGetActionImpl{} - action.Verb = "get" - action.Resource = resource - action.Namespace = namespace - action.Scheme = scheme - action.Name = name - action.Port = port - action.Path = path - action.Params = params - return action -} - -type ListRestrictions struct { - Labels labels.Selector - Fields fields.Selector -} -type WatchRestrictions struct { - Labels labels.Selector - Fields fields.Selector - ResourceVersion string -} - -type Action interface { - GetNamespace() string - GetVerb() string - GetResource() schema.GroupVersionResource - GetSubresource() string - Matches(verb, resource string) bool - - // DeepCopy is used to copy an action to avoid any risk of accidental mutation. Most people never need to call this - // because the invocation logic deep copies before calls to storage and reactors. - DeepCopy() Action -} - -type GenericAction interface { - Action - GetValue() interface{} -} - -type GetAction interface { - Action - GetName() string -} - -type ListAction interface { - Action - GetListRestrictions() ListRestrictions -} - -type CreateAction interface { - Action - GetObject() runtime.Object -} - -type UpdateAction interface { - Action - GetObject() runtime.Object -} - -type DeleteAction interface { - Action - GetName() string - GetDeleteOptions() metav1.DeleteOptions -} - -type DeleteCollectionAction interface { - Action - GetListRestrictions() ListRestrictions -} - -type PatchAction interface { - Action - GetName() string - GetPatchType() types.PatchType - GetPatch() []byte -} - -type WatchAction interface { - Action - GetWatchRestrictions() WatchRestrictions -} - -type ProxyGetAction interface { - Action - GetScheme() string - GetName() string - GetPort() string - GetPath() string - GetParams() map[string]string -} - -type ActionImpl struct { - Namespace string - Verb string - Resource schema.GroupVersionResource - Subresource string -} - -func (a ActionImpl) GetNamespace() string { - return a.Namespace -} -func (a ActionImpl) GetVerb() string { - return a.Verb -} -func (a ActionImpl) GetResource() schema.GroupVersionResource { - return a.Resource -} -func (a ActionImpl) GetSubresource() string { - return a.Subresource -} -func (a ActionImpl) Matches(verb, resource string) bool { - // Stay backwards compatible. - if !strings.Contains(resource, "/") { - return strings.EqualFold(verb, a.Verb) && - strings.EqualFold(resource, a.Resource.Resource) - } - - parts := strings.SplitN(resource, "/", 2) - topresource, subresource := parts[0], parts[1] - - return strings.EqualFold(verb, a.Verb) && - strings.EqualFold(topresource, a.Resource.Resource) && - strings.EqualFold(subresource, a.Subresource) -} -func (a ActionImpl) DeepCopy() Action { - ret := a - return ret -} - -type GenericActionImpl struct { - ActionImpl - Value interface{} -} - -func (a GenericActionImpl) GetValue() interface{} { - return a.Value -} - -func (a GenericActionImpl) DeepCopy() Action { - return GenericActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - // TODO this is wrong, but no worse than before - Value: a.Value, - } -} - -type GetActionImpl struct { - ActionImpl - Name string -} - -func (a GetActionImpl) GetName() string { - return a.Name -} - -func (a GetActionImpl) DeepCopy() Action { - return GetActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Name: a.Name, - } -} - -type ListActionImpl struct { - ActionImpl - Kind schema.GroupVersionKind - Name string - ListRestrictions ListRestrictions -} - -func (a ListActionImpl) GetKind() schema.GroupVersionKind { - return a.Kind -} - -func (a ListActionImpl) GetListRestrictions() ListRestrictions { - return a.ListRestrictions -} - -func (a ListActionImpl) DeepCopy() Action { - return ListActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Kind: a.Kind, - Name: a.Name, - ListRestrictions: ListRestrictions{ - Labels: a.ListRestrictions.Labels.DeepCopySelector(), - Fields: a.ListRestrictions.Fields.DeepCopySelector(), - }, - } -} - -type CreateActionImpl struct { - ActionImpl - Name string - Object runtime.Object -} - -func (a CreateActionImpl) GetObject() runtime.Object { - return a.Object -} - -func (a CreateActionImpl) DeepCopy() Action { - return CreateActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Name: a.Name, - Object: a.Object.DeepCopyObject(), - } -} - -type UpdateActionImpl struct { - ActionImpl - Object runtime.Object -} - -func (a UpdateActionImpl) GetObject() runtime.Object { - return a.Object -} - -func (a UpdateActionImpl) DeepCopy() Action { - return UpdateActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Object: a.Object.DeepCopyObject(), - } -} - -type PatchActionImpl struct { - ActionImpl - Name string - PatchType types.PatchType - Patch []byte -} - -func (a PatchActionImpl) GetName() string { - return a.Name -} - -func (a PatchActionImpl) GetPatch() []byte { - return a.Patch -} - -func (a PatchActionImpl) GetPatchType() types.PatchType { - return a.PatchType -} - -func (a PatchActionImpl) DeepCopy() Action { - patch := make([]byte, len(a.Patch)) - copy(patch, a.Patch) - return PatchActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Name: a.Name, - PatchType: a.PatchType, - Patch: patch, - } -} - -type DeleteActionImpl struct { - ActionImpl - Name string - DeleteOptions metav1.DeleteOptions -} - -func (a DeleteActionImpl) GetName() string { - return a.Name -} - -func (a DeleteActionImpl) GetDeleteOptions() metav1.DeleteOptions { - return a.DeleteOptions -} - -func (a DeleteActionImpl) DeepCopy() Action { - return DeleteActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Name: a.Name, - DeleteOptions: *a.DeleteOptions.DeepCopy(), - } -} - -type DeleteCollectionActionImpl struct { - ActionImpl - ListRestrictions ListRestrictions -} - -func (a DeleteCollectionActionImpl) GetListRestrictions() ListRestrictions { - return a.ListRestrictions -} - -func (a DeleteCollectionActionImpl) DeepCopy() Action { - return DeleteCollectionActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - ListRestrictions: ListRestrictions{ - Labels: a.ListRestrictions.Labels.DeepCopySelector(), - Fields: a.ListRestrictions.Fields.DeepCopySelector(), - }, - } -} - -type WatchActionImpl struct { - ActionImpl - WatchRestrictions WatchRestrictions -} - -func (a WatchActionImpl) GetWatchRestrictions() WatchRestrictions { - return a.WatchRestrictions -} - -func (a WatchActionImpl) DeepCopy() Action { - return WatchActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - WatchRestrictions: WatchRestrictions{ - Labels: a.WatchRestrictions.Labels.DeepCopySelector(), - Fields: a.WatchRestrictions.Fields.DeepCopySelector(), - ResourceVersion: a.WatchRestrictions.ResourceVersion, - }, - } -} - -type ProxyGetActionImpl struct { - ActionImpl - Scheme string - Name string - Port string - Path string - Params map[string]string -} - -func (a ProxyGetActionImpl) GetScheme() string { - return a.Scheme -} - -func (a ProxyGetActionImpl) GetName() string { - return a.Name -} - -func (a ProxyGetActionImpl) GetPort() string { - return a.Port -} - -func (a ProxyGetActionImpl) GetPath() string { - return a.Path -} - -func (a ProxyGetActionImpl) GetParams() map[string]string { - return a.Params -} - -func (a ProxyGetActionImpl) DeepCopy() Action { - params := map[string]string{} - for k, v := range a.Params { - params[k] = v - } - return ProxyGetActionImpl{ - ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), - Scheme: a.Scheme, - Name: a.Name, - Port: a.Port, - Path: a.Path, - Params: params, - } -} diff --git a/operator/vendor/k8s.io/client-go/testing/fake.go b/operator/vendor/k8s.io/client-go/testing/fake.go deleted file mode 100644 index 3ab9c1b0..00000000 --- a/operator/vendor/k8s.io/client-go/testing/fake.go +++ /dev/null @@ -1,220 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package testing - -import ( - "fmt" - "sync" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - restclient "k8s.io/client-go/rest" -) - -// Fake implements client.Interface. Meant to be embedded into a struct to get -// a default implementation. This makes faking out just the method you want to -// test easier. -type Fake struct { - sync.RWMutex - actions []Action // these may be castable to other types, but "Action" is the minimum - - // ReactionChain is the list of reactors that will be attempted for every - // request in the order they are tried. - ReactionChain []Reactor - // WatchReactionChain is the list of watch reactors that will be attempted - // for every request in the order they are tried. - WatchReactionChain []WatchReactor - // ProxyReactionChain is the list of proxy reactors that will be attempted - // for every request in the order they are tried. - ProxyReactionChain []ProxyReactor - - Resources []*metav1.APIResourceList -} - -// Reactor is an interface to allow the composition of reaction functions. -type Reactor interface { - // Handles indicates whether or not this Reactor deals with a given - // action. - Handles(action Action) bool - // React handles the action and returns results. It may choose to - // delegate by indicated handled=false. - React(action Action) (handled bool, ret runtime.Object, err error) -} - -// WatchReactor is an interface to allow the composition of watch functions. -type WatchReactor interface { - // Handles indicates whether or not this Reactor deals with a given - // action. - Handles(action Action) bool - // React handles a watch action and returns results. It may choose to - // delegate by indicating handled=false. - React(action Action) (handled bool, ret watch.Interface, err error) -} - -// ProxyReactor is an interface to allow the composition of proxy get -// functions. -type ProxyReactor interface { - // Handles indicates whether or not this Reactor deals with a given - // action. - Handles(action Action) bool - // React handles a watch action and returns results. It may choose to - // delegate by indicating handled=false. - React(action Action) (handled bool, ret restclient.ResponseWrapper, err error) -} - -// ReactionFunc is a function that returns an object or error for a given -// Action. If "handled" is false, then the test client will ignore the -// results and continue to the next ReactionFunc. A ReactionFunc can describe -// reactions on subresources by testing the result of the action's -// GetSubresource() method. -type ReactionFunc func(action Action) (handled bool, ret runtime.Object, err error) - -// WatchReactionFunc is a function that returns a watch interface. If -// "handled" is false, then the test client will ignore the results and -// continue to the next ReactionFunc. -type WatchReactionFunc func(action Action) (handled bool, ret watch.Interface, err error) - -// ProxyReactionFunc is a function that returns a ResponseWrapper interface -// for a given Action. If "handled" is false, then the test client will -// ignore the results and continue to the next ProxyReactionFunc. -type ProxyReactionFunc func(action Action) (handled bool, ret restclient.ResponseWrapper, err error) - -// AddReactor appends a reactor to the end of the chain. -func (c *Fake) AddReactor(verb, resource string, reaction ReactionFunc) { - c.ReactionChain = append(c.ReactionChain, &SimpleReactor{verb, resource, reaction}) -} - -// PrependReactor adds a reactor to the beginning of the chain. -func (c *Fake) PrependReactor(verb, resource string, reaction ReactionFunc) { - c.ReactionChain = append([]Reactor{&SimpleReactor{verb, resource, reaction}}, c.ReactionChain...) -} - -// AddWatchReactor appends a reactor to the end of the chain. -func (c *Fake) AddWatchReactor(resource string, reaction WatchReactionFunc) { - c.Lock() - defer c.Unlock() - c.WatchReactionChain = append(c.WatchReactionChain, &SimpleWatchReactor{resource, reaction}) -} - -// PrependWatchReactor adds a reactor to the beginning of the chain. -func (c *Fake) PrependWatchReactor(resource string, reaction WatchReactionFunc) { - c.Lock() - defer c.Unlock() - c.WatchReactionChain = append([]WatchReactor{&SimpleWatchReactor{resource, reaction}}, c.WatchReactionChain...) -} - -// AddProxyReactor appends a reactor to the end of the chain. -func (c *Fake) AddProxyReactor(resource string, reaction ProxyReactionFunc) { - c.ProxyReactionChain = append(c.ProxyReactionChain, &SimpleProxyReactor{resource, reaction}) -} - -// PrependProxyReactor adds a reactor to the beginning of the chain. -func (c *Fake) PrependProxyReactor(resource string, reaction ProxyReactionFunc) { - c.ProxyReactionChain = append([]ProxyReactor{&SimpleProxyReactor{resource, reaction}}, c.ProxyReactionChain...) -} - -// Invokes records the provided Action and then invokes the ReactionFunc that -// handles the action if one exists. defaultReturnObj is expected to be of the -// same type a normal call would return. -func (c *Fake) Invokes(action Action, defaultReturnObj runtime.Object) (runtime.Object, error) { - c.Lock() - defer c.Unlock() - - actionCopy := action.DeepCopy() - c.actions = append(c.actions, action.DeepCopy()) - for _, reactor := range c.ReactionChain { - if !reactor.Handles(actionCopy) { - continue - } - - handled, ret, err := reactor.React(actionCopy) - if !handled { - continue - } - - return ret, err - } - - return defaultReturnObj, nil -} - -// InvokesWatch records the provided Action and then invokes the ReactionFunc -// that handles the action if one exists. -func (c *Fake) InvokesWatch(action Action) (watch.Interface, error) { - c.Lock() - defer c.Unlock() - - actionCopy := action.DeepCopy() - c.actions = append(c.actions, action.DeepCopy()) - for _, reactor := range c.WatchReactionChain { - if !reactor.Handles(actionCopy) { - continue - } - - handled, ret, err := reactor.React(actionCopy) - if !handled { - continue - } - - return ret, err - } - - return nil, fmt.Errorf("unhandled watch: %#v", action) -} - -// InvokesProxy records the provided Action and then invokes the ReactionFunc -// that handles the action if one exists. -func (c *Fake) InvokesProxy(action Action) restclient.ResponseWrapper { - c.Lock() - defer c.Unlock() - - actionCopy := action.DeepCopy() - c.actions = append(c.actions, action.DeepCopy()) - for _, reactor := range c.ProxyReactionChain { - if !reactor.Handles(actionCopy) { - continue - } - - handled, ret, err := reactor.React(actionCopy) - if !handled || err != nil { - continue - } - - return ret - } - - return nil -} - -// ClearActions clears the history of actions called on the fake client. -func (c *Fake) ClearActions() { - c.Lock() - defer c.Unlock() - - c.actions = make([]Action, 0) -} - -// Actions returns a chronologically ordered slice fake actions called on the -// fake client. -func (c *Fake) Actions() []Action { - c.RLock() - defer c.RUnlock() - fa := make([]Action, len(c.actions)) - copy(fa, c.actions) - return fa -} diff --git a/operator/vendor/k8s.io/client-go/testing/fixture.go b/operator/vendor/k8s.io/client-go/testing/fixture.go deleted file mode 100644 index 39684067..00000000 --- a/operator/vendor/k8s.io/client-go/testing/fixture.go +++ /dev/null @@ -1,581 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package testing - -import ( - "fmt" - "reflect" - "sort" - "strings" - "sync" - - jsonpatch "github.com/evanphx/json-patch" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/apimachinery/pkg/util/strategicpatch" - "k8s.io/apimachinery/pkg/watch" - restclient "k8s.io/client-go/rest" -) - -// ObjectTracker keeps track of objects. It is intended to be used to -// fake calls to a server by returning objects based on their kind, -// namespace and name. -type ObjectTracker interface { - // Add adds an object to the tracker. If object being added - // is a list, its items are added separately. - Add(obj runtime.Object) error - - // Get retrieves the object by its kind, namespace and name. - Get(gvr schema.GroupVersionResource, ns, name string) (runtime.Object, error) - - // Create adds an object to the tracker in the specified namespace. - Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error - - // Update updates an existing object in the tracker in the specified namespace. - Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error - - // List retrieves all objects of a given kind in the given - // namespace. Only non-List kinds are accepted. - List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string) (runtime.Object, error) - - // Delete deletes an existing object from the tracker. If object - // didn't exist in the tracker prior to deletion, Delete returns - // no error. - Delete(gvr schema.GroupVersionResource, ns, name string) error - - // Watch watches objects from the tracker. Watch returns a channel - // which will push added / modified / deleted object. - Watch(gvr schema.GroupVersionResource, ns string) (watch.Interface, error) -} - -// ObjectScheme abstracts the implementation of common operations on objects. -type ObjectScheme interface { - runtime.ObjectCreater - runtime.ObjectTyper -} - -// ObjectReaction returns a ReactionFunc that applies core.Action to -// the given tracker. -func ObjectReaction(tracker ObjectTracker) ReactionFunc { - return func(action Action) (bool, runtime.Object, error) { - ns := action.GetNamespace() - gvr := action.GetResource() - // Here and below we need to switch on implementation types, - // not on interfaces, as some interfaces are identical - // (e.g. UpdateAction and CreateAction), so if we use them, - // updates and creates end up matching the same case branch. - switch action := action.(type) { - - case ListActionImpl: - obj, err := tracker.List(gvr, action.GetKind(), ns) - return true, obj, err - - case GetActionImpl: - obj, err := tracker.Get(gvr, ns, action.GetName()) - return true, obj, err - - case CreateActionImpl: - objMeta, err := meta.Accessor(action.GetObject()) - if err != nil { - return true, nil, err - } - if action.GetSubresource() == "" { - err = tracker.Create(gvr, action.GetObject(), ns) - } else { - oldObj, getOldObjErr := tracker.Get(gvr, ns, objMeta.GetName()) - if getOldObjErr != nil { - return true, nil, getOldObjErr - } - // Check whether the existing historical object type is the same as the current operation object type that needs to be updated, and if it is the same, perform the update operation. - if reflect.TypeOf(oldObj) == reflect.TypeOf(action.GetObject()) { - // TODO: Currently we're handling subresource creation as an update - // on the enclosing resource. This works for some subresources but - // might not be generic enough. - err = tracker.Update(gvr, action.GetObject(), ns) - } else { - // If the historical object type is different from the current object type, need to make sure we return the object submitted,don't persist the submitted object in the tracker. - return true, action.GetObject(), nil - } - } - if err != nil { - return true, nil, err - } - obj, err := tracker.Get(gvr, ns, objMeta.GetName()) - return true, obj, err - - case UpdateActionImpl: - objMeta, err := meta.Accessor(action.GetObject()) - if err != nil { - return true, nil, err - } - err = tracker.Update(gvr, action.GetObject(), ns) - if err != nil { - return true, nil, err - } - obj, err := tracker.Get(gvr, ns, objMeta.GetName()) - return true, obj, err - - case DeleteActionImpl: - err := tracker.Delete(gvr, ns, action.GetName()) - if err != nil { - return true, nil, err - } - return true, nil, nil - - case PatchActionImpl: - obj, err := tracker.Get(gvr, ns, action.GetName()) - if err != nil { - return true, nil, err - } - - old, err := json.Marshal(obj) - if err != nil { - return true, nil, err - } - - // reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields - // in obj that are removed by patch are cleared - value := reflect.ValueOf(obj) - value.Elem().Set(reflect.New(value.Type().Elem()).Elem()) - - switch action.GetPatchType() { - case types.JSONPatchType: - patch, err := jsonpatch.DecodePatch(action.GetPatch()) - if err != nil { - return true, nil, err - } - modified, err := patch.Apply(old) - if err != nil { - return true, nil, err - } - - if err = json.Unmarshal(modified, obj); err != nil { - return true, nil, err - } - case types.MergePatchType: - modified, err := jsonpatch.MergePatch(old, action.GetPatch()) - if err != nil { - return true, nil, err - } - - if err := json.Unmarshal(modified, obj); err != nil { - return true, nil, err - } - case types.StrategicMergePatchType, types.ApplyPatchType: - mergedByte, err := strategicpatch.StrategicMergePatch(old, action.GetPatch(), obj) - if err != nil { - return true, nil, err - } - if err = json.Unmarshal(mergedByte, obj); err != nil { - return true, nil, err - } - default: - return true, nil, fmt.Errorf("PatchType is not supported") - } - - if err = tracker.Update(gvr, obj, ns); err != nil { - return true, nil, err - } - - return true, obj, nil - - default: - return false, nil, fmt.Errorf("no reaction implemented for %s", action) - } - } -} - -type tracker struct { - scheme ObjectScheme - decoder runtime.Decoder - lock sync.RWMutex - objects map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object - // The value type of watchers is a map of which the key is either a namespace or - // all/non namespace aka "" and its value is list of fake watchers. - // Manipulations on resources will broadcast the notification events into the - // watchers' channel. Note that too many unhandled events (currently 100, - // see apimachinery/pkg/watch.DefaultChanSize) will cause a panic. - watchers map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher -} - -var _ ObjectTracker = &tracker{} - -// NewObjectTracker returns an ObjectTracker that can be used to keep track -// of objects for the fake clientset. Mostly useful for unit tests. -func NewObjectTracker(scheme ObjectScheme, decoder runtime.Decoder) ObjectTracker { - return &tracker{ - scheme: scheme, - decoder: decoder, - objects: make(map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object), - watchers: make(map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher), - } -} - -func (t *tracker) List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string) (runtime.Object, error) { - // Heuristic for list kind: original kind + List suffix. Might - // not always be true but this tracker has a pretty limited - // understanding of the actual API model. - listGVK := gvk - listGVK.Kind = listGVK.Kind + "List" - // GVK does have the concept of "internal version". The scheme recognizes - // the runtime.APIVersionInternal, but not the empty string. - if listGVK.Version == "" { - listGVK.Version = runtime.APIVersionInternal - } - - list, err := t.scheme.New(listGVK) - if err != nil { - return nil, err - } - - if !meta.IsListType(list) { - return nil, fmt.Errorf("%q is not a list type", listGVK.Kind) - } - - t.lock.RLock() - defer t.lock.RUnlock() - - objs, ok := t.objects[gvr] - if !ok { - return list, nil - } - - matchingObjs, err := filterByNamespace(objs, ns) - if err != nil { - return nil, err - } - if err := meta.SetList(list, matchingObjs); err != nil { - return nil, err - } - return list.DeepCopyObject(), nil -} - -func (t *tracker) Watch(gvr schema.GroupVersionResource, ns string) (watch.Interface, error) { - t.lock.Lock() - defer t.lock.Unlock() - - fakewatcher := watch.NewRaceFreeFake() - - if _, exists := t.watchers[gvr]; !exists { - t.watchers[gvr] = make(map[string][]*watch.RaceFreeFakeWatcher) - } - t.watchers[gvr][ns] = append(t.watchers[gvr][ns], fakewatcher) - return fakewatcher, nil -} - -func (t *tracker) Get(gvr schema.GroupVersionResource, ns, name string) (runtime.Object, error) { - errNotFound := errors.NewNotFound(gvr.GroupResource(), name) - - t.lock.RLock() - defer t.lock.RUnlock() - - objs, ok := t.objects[gvr] - if !ok { - return nil, errNotFound - } - - matchingObj, ok := objs[types.NamespacedName{Namespace: ns, Name: name}] - if !ok { - return nil, errNotFound - } - - // Only one object should match in the tracker if it works - // correctly, as Add/Update methods enforce kind/namespace/name - // uniqueness. - obj := matchingObj.DeepCopyObject() - if status, ok := obj.(*metav1.Status); ok { - if status.Status != metav1.StatusSuccess { - return nil, &errors.StatusError{ErrStatus: *status} - } - } - - return obj, nil -} - -func (t *tracker) Add(obj runtime.Object) error { - if meta.IsListType(obj) { - return t.addList(obj, false) - } - objMeta, err := meta.Accessor(obj) - if err != nil { - return err - } - gvks, _, err := t.scheme.ObjectKinds(obj) - if err != nil { - return err - } - - if partial, ok := obj.(*metav1.PartialObjectMetadata); ok && len(partial.TypeMeta.APIVersion) > 0 { - gvks = []schema.GroupVersionKind{partial.TypeMeta.GroupVersionKind()} - } - - if len(gvks) == 0 { - return fmt.Errorf("no registered kinds for %v", obj) - } - for _, gvk := range gvks { - // NOTE: UnsafeGuessKindToResource is a heuristic and default match. The - // actual registration in apiserver can specify arbitrary route for a - // gvk. If a test uses such objects, it cannot preset the tracker with - // objects via Add(). Instead, it should trigger the Create() function - // of the tracker, where an arbitrary gvr can be specified. - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - // Resource doesn't have the concept of "__internal" version, just set it to "". - if gvr.Version == runtime.APIVersionInternal { - gvr.Version = "" - } - - err := t.add(gvr, obj, objMeta.GetNamespace(), false) - if err != nil { - return err - } - } - return nil -} - -func (t *tracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error { - return t.add(gvr, obj, ns, false) -} - -func (t *tracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error { - return t.add(gvr, obj, ns, true) -} - -func (t *tracker) getWatches(gvr schema.GroupVersionResource, ns string) []*watch.RaceFreeFakeWatcher { - watches := []*watch.RaceFreeFakeWatcher{} - if t.watchers[gvr] != nil { - if w := t.watchers[gvr][ns]; w != nil { - watches = append(watches, w...) - } - if ns != metav1.NamespaceAll { - if w := t.watchers[gvr][metav1.NamespaceAll]; w != nil { - watches = append(watches, w...) - } - } - } - return watches -} - -func (t *tracker) add(gvr schema.GroupVersionResource, obj runtime.Object, ns string, replaceExisting bool) error { - t.lock.Lock() - defer t.lock.Unlock() - - gr := gvr.GroupResource() - - // To avoid the object from being accidentally modified by caller - // after it's been added to the tracker, we always store the deep - // copy. - obj = obj.DeepCopyObject() - - newMeta, err := meta.Accessor(obj) - if err != nil { - return err - } - - // Propagate namespace to the new object if hasn't already been set. - if len(newMeta.GetNamespace()) == 0 { - newMeta.SetNamespace(ns) - } - - if ns != newMeta.GetNamespace() { - msg := fmt.Sprintf("request namespace does not match object namespace, request: %q object: %q", ns, newMeta.GetNamespace()) - return errors.NewBadRequest(msg) - } - - _, ok := t.objects[gvr] - if !ok { - t.objects[gvr] = make(map[types.NamespacedName]runtime.Object) - } - - namespacedName := types.NamespacedName{Namespace: newMeta.GetNamespace(), Name: newMeta.GetName()} - if _, ok = t.objects[gvr][namespacedName]; ok { - if replaceExisting { - for _, w := range t.getWatches(gvr, ns) { - // To avoid the object from being accidentally modified by watcher - w.Modify(obj.DeepCopyObject()) - } - t.objects[gvr][namespacedName] = obj - return nil - } - return errors.NewAlreadyExists(gr, newMeta.GetName()) - } - - if replaceExisting { - // Tried to update but no matching object was found. - return errors.NewNotFound(gr, newMeta.GetName()) - } - - t.objects[gvr][namespacedName] = obj - - for _, w := range t.getWatches(gvr, ns) { - // To avoid the object from being accidentally modified by watcher - w.Add(obj.DeepCopyObject()) - } - - return nil -} - -func (t *tracker) addList(obj runtime.Object, replaceExisting bool) error { - list, err := meta.ExtractList(obj) - if err != nil { - return err - } - errs := runtime.DecodeList(list, t.decoder) - if len(errs) > 0 { - return errs[0] - } - for _, obj := range list { - if err := t.Add(obj); err != nil { - return err - } - } - return nil -} - -func (t *tracker) Delete(gvr schema.GroupVersionResource, ns, name string) error { - t.lock.Lock() - defer t.lock.Unlock() - - objs, ok := t.objects[gvr] - if !ok { - return errors.NewNotFound(gvr.GroupResource(), name) - } - - namespacedName := types.NamespacedName{Namespace: ns, Name: name} - obj, ok := objs[namespacedName] - if !ok { - return errors.NewNotFound(gvr.GroupResource(), name) - } - - delete(objs, namespacedName) - for _, w := range t.getWatches(gvr, ns) { - w.Delete(obj.DeepCopyObject()) - } - return nil -} - -// filterByNamespace returns all objects in the collection that -// match provided namespace. Empty namespace matches -// non-namespaced objects. -func filterByNamespace(objs map[types.NamespacedName]runtime.Object, ns string) ([]runtime.Object, error) { - var res []runtime.Object - - for _, obj := range objs { - acc, err := meta.Accessor(obj) - if err != nil { - return nil, err - } - if ns != "" && acc.GetNamespace() != ns { - continue - } - res = append(res, obj) - } - - // Sort res to get deterministic order. - sort.Slice(res, func(i, j int) bool { - acc1, _ := meta.Accessor(res[i]) - acc2, _ := meta.Accessor(res[j]) - if acc1.GetNamespace() != acc2.GetNamespace() { - return acc1.GetNamespace() < acc2.GetNamespace() - } - return acc1.GetName() < acc2.GetName() - }) - return res, nil -} - -func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc { - return func(action Action) (bool, watch.Interface, error) { - return true, watchInterface, err - } -} - -// SimpleReactor is a Reactor. Each reaction function is attached to a given verb,resource tuple. "*" in either field matches everything for that value. -// For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions -type SimpleReactor struct { - Verb string - Resource string - - Reaction ReactionFunc -} - -func (r *SimpleReactor) Handles(action Action) bool { - verbCovers := r.Verb == "*" || r.Verb == action.GetVerb() - if !verbCovers { - return false - } - - return resourceCovers(r.Resource, action) -} - -func (r *SimpleReactor) React(action Action) (bool, runtime.Object, error) { - return r.Reaction(action) -} - -// SimpleWatchReactor is a WatchReactor. Each reaction function is attached to a given resource. "*" matches everything for that value. -// For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions -type SimpleWatchReactor struct { - Resource string - - Reaction WatchReactionFunc -} - -func (r *SimpleWatchReactor) Handles(action Action) bool { - return resourceCovers(r.Resource, action) -} - -func (r *SimpleWatchReactor) React(action Action) (bool, watch.Interface, error) { - return r.Reaction(action) -} - -// SimpleProxyReactor is a ProxyReactor. Each reaction function is attached to a given resource. "*" matches everything for that value. -// For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions. -type SimpleProxyReactor struct { - Resource string - - Reaction ProxyReactionFunc -} - -func (r *SimpleProxyReactor) Handles(action Action) bool { - return resourceCovers(r.Resource, action) -} - -func (r *SimpleProxyReactor) React(action Action) (bool, restclient.ResponseWrapper, error) { - return r.Reaction(action) -} - -func resourceCovers(resource string, action Action) bool { - if resource == "*" { - return true - } - - if resource == action.GetResource().Resource { - return true - } - - if index := strings.Index(resource, "/"); index != -1 && - resource[:index] == action.GetResource().Resource && - resource[index+1:] == action.GetSubresource() { - return true - } - - return false -} diff --git a/operator/vendor/k8s.io/client-go/testing/interface.go b/operator/vendor/k8s.io/client-go/testing/interface.go deleted file mode 100644 index 266c6ba3..00000000 --- a/operator/vendor/k8s.io/client-go/testing/interface.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package testing - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - restclient "k8s.io/client-go/rest" -) - -type FakeClient interface { - // Tracker gives access to the ObjectTracker internal to the fake client. - Tracker() ObjectTracker - - // AddReactor appends a reactor to the end of the chain. - AddReactor(verb, resource string, reaction ReactionFunc) - - // PrependReactor adds a reactor to the beginning of the chain. - PrependReactor(verb, resource string, reaction ReactionFunc) - - // AddWatchReactor appends a reactor to the end of the chain. - AddWatchReactor(resource string, reaction WatchReactionFunc) - - // PrependWatchReactor adds a reactor to the beginning of the chain. - PrependWatchReactor(resource string, reaction WatchReactionFunc) - - // AddProxyReactor appends a reactor to the end of the chain. - AddProxyReactor(resource string, reaction ProxyReactionFunc) - - // PrependProxyReactor adds a reactor to the beginning of the chain. - PrependProxyReactor(resource string, reaction ProxyReactionFunc) - - // Invokes records the provided Action and then invokes the ReactionFunc that - // handles the action if one exists. defaultReturnObj is expected to be of the - // same type a normal call would return. - Invokes(action Action, defaultReturnObj runtime.Object) (runtime.Object, error) - - // InvokesWatch records the provided Action and then invokes the ReactionFunc - // that handles the action if one exists. - InvokesWatch(action Action) (watch.Interface, error) - - // InvokesProxy records the provided Action and then invokes the ReactionFunc - // that handles the action if one exists. - InvokesProxy(action Action) restclient.ResponseWrapper - - // ClearActions clears the history of actions called on the fake client. - ClearActions() - - // Actions returns a chronologically ordered slice fake actions called on the - // fake client. - Actions() []Action -} diff --git a/operator/vendor/modules.txt b/operator/vendor/modules.txt index 98f23d99..a67c1fed 100644 --- a/operator/vendor/modules.txt +++ b/operator/vendor/modules.txt @@ -11,9 +11,6 @@ github.com/davecgh/go-spew/spew ## explicit; go 1.13 github.com/emicklei/go-restful/v3 github.com/emicklei/go-restful/v3/log -# github.com/evanphx/json-patch v5.6.0+incompatible -## explicit -github.com/evanphx/json-patch # github.com/evanphx/json-patch/v5 v5.8.0 ## explicit; go 1.18 github.com/evanphx/json-patch/v5 @@ -422,7 +419,6 @@ k8s.io/apimachinery/pkg/util/managedfields/internal k8s.io/apimachinery/pkg/util/mergepatch k8s.io/apimachinery/pkg/util/naming k8s.io/apimachinery/pkg/util/net -k8s.io/apimachinery/pkg/util/rand k8s.io/apimachinery/pkg/util/runtime k8s.io/apimachinery/pkg/util/sets k8s.io/apimachinery/pkg/util/strategicpatch @@ -555,7 +551,6 @@ k8s.io/client-go/plugin/pkg/client/auth/oidc k8s.io/client-go/rest k8s.io/client-go/rest/watch k8s.io/client-go/restmapper -k8s.io/client-go/testing k8s.io/client-go/tools/auth k8s.io/client-go/tools/cache k8s.io/client-go/tools/cache/synctrack @@ -617,20 +612,16 @@ k8s.io/utils/trace sigs.k8s.io/controller-runtime sigs.k8s.io/controller-runtime/pkg/builder sigs.k8s.io/controller-runtime/pkg/cache -sigs.k8s.io/controller-runtime/pkg/cache/informertest sigs.k8s.io/controller-runtime/pkg/cache/internal sigs.k8s.io/controller-runtime/pkg/certwatcher sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics sigs.k8s.io/controller-runtime/pkg/client sigs.k8s.io/controller-runtime/pkg/client/apiutil sigs.k8s.io/controller-runtime/pkg/client/config -sigs.k8s.io/controller-runtime/pkg/client/fake -sigs.k8s.io/controller-runtime/pkg/client/interceptor sigs.k8s.io/controller-runtime/pkg/cluster sigs.k8s.io/controller-runtime/pkg/config sigs.k8s.io/controller-runtime/pkg/config/v1alpha1 sigs.k8s.io/controller-runtime/pkg/controller -sigs.k8s.io/controller-runtime/pkg/controller/controllertest sigs.k8s.io/controller-runtime/pkg/controller/controllerutil sigs.k8s.io/controller-runtime/pkg/conversion sigs.k8s.io/controller-runtime/pkg/event @@ -641,7 +632,6 @@ sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics sigs.k8s.io/controller-runtime/pkg/internal/field/selector sigs.k8s.io/controller-runtime/pkg/internal/httpserver sigs.k8s.io/controller-runtime/pkg/internal/log -sigs.k8s.io/controller-runtime/pkg/internal/objectutil sigs.k8s.io/controller-runtime/pkg/internal/recorder sigs.k8s.io/controller-runtime/pkg/internal/source sigs.k8s.io/controller-runtime/pkg/leaderelection diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informertest/fake_cache.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informertest/fake_cache.go deleted file mode 100644 index 17111769..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informertest/fake_cache.go +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package informertest - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/kubernetes/scheme" - toolscache "k8s.io/client-go/tools/cache" - - "sigs.k8s.io/controller-runtime/pkg/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllertest" -) - -var _ cache.Cache = &FakeInformers{} - -// FakeInformers is a fake implementation of Informers. -type FakeInformers struct { - InformersByGVK map[schema.GroupVersionKind]toolscache.SharedIndexInformer - Scheme *runtime.Scheme - Error error - Synced *bool -} - -// GetInformerForKind implements Informers. -func (c *FakeInformers) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...cache.InformerGetOption) (cache.Informer, error) { - if c.Scheme == nil { - c.Scheme = scheme.Scheme - } - obj, err := c.Scheme.New(gvk) - if err != nil { - return nil, err - } - return c.informerFor(gvk, obj) -} - -// FakeInformerForKind implements Informers. -func (c *FakeInformers) FakeInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (*controllertest.FakeInformer, error) { - i, err := c.GetInformerForKind(ctx, gvk) - if err != nil { - return nil, err - } - return i.(*controllertest.FakeInformer), nil -} - -// GetInformer implements Informers. -func (c *FakeInformers) GetInformer(ctx context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error) { - if c.Scheme == nil { - c.Scheme = scheme.Scheme - } - gvks, _, err := c.Scheme.ObjectKinds(obj) - if err != nil { - return nil, err - } - gvk := gvks[0] - return c.informerFor(gvk, obj) -} - -// WaitForCacheSync implements Informers. -func (c *FakeInformers) WaitForCacheSync(ctx context.Context) bool { - if c.Synced == nil { - return true - } - return *c.Synced -} - -// FakeInformerFor implements Informers. -func (c *FakeInformers) FakeInformerFor(ctx context.Context, obj client.Object) (*controllertest.FakeInformer, error) { - i, err := c.GetInformer(ctx, obj) - if err != nil { - return nil, err - } - return i.(*controllertest.FakeInformer), nil -} - -func (c *FakeInformers) informerFor(gvk schema.GroupVersionKind, _ runtime.Object) (toolscache.SharedIndexInformer, error) { - if c.Error != nil { - return nil, c.Error - } - if c.InformersByGVK == nil { - c.InformersByGVK = map[schema.GroupVersionKind]toolscache.SharedIndexInformer{} - } - informer, ok := c.InformersByGVK[gvk] - if ok { - return informer, nil - } - - c.InformersByGVK[gvk] = &controllertest.FakeInformer{} - return c.InformersByGVK[gvk], nil -} - -// Start implements Informers. -func (c *FakeInformers) Start(ctx context.Context) error { - return c.Error -} - -// IndexField implements Cache. -func (c *FakeInformers) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error { - return nil -} - -// Get implements Cache. -func (c *FakeInformers) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - return nil -} - -// List implements Cache. -func (c *FakeInformers) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - return nil -} diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go deleted file mode 100644 index 9deb6756..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go +++ /dev/null @@ -1,1260 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package fake - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "reflect" - "runtime/debug" - "strconv" - "strings" - "sync" - "time" - - // Using v4 to match upstream - jsonpatch "github.com/evanphx/json-patch" - corev1 "k8s.io/api/core/v1" - policyv1 "k8s.io/api/policy/v1" - policyv1beta1 "k8s.io/api/policy/v1beta1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - utilrand "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/strategicpatch" - "k8s.io/apimachinery/pkg/util/validation/field" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/testing" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - "sigs.k8s.io/controller-runtime/pkg/client/interceptor" - "sigs.k8s.io/controller-runtime/pkg/internal/field/selector" - "sigs.k8s.io/controller-runtime/pkg/internal/objectutil" -) - -type versionedTracker struct { - testing.ObjectTracker - scheme *runtime.Scheme - withStatusSubresource sets.Set[schema.GroupVersionKind] -} - -type fakeClient struct { - tracker versionedTracker - scheme *runtime.Scheme - restMapper meta.RESTMapper - withStatusSubresource sets.Set[schema.GroupVersionKind] - - // indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK. - // The inner map maps from index name to IndexerFunc. - indexes map[schema.GroupVersionKind]map[string]client.IndexerFunc - - schemeWriteLock sync.Mutex -} - -var _ client.WithWatch = &fakeClient{} - -const ( - maxNameLength = 63 - randomLength = 5 - maxGeneratedNameLength = maxNameLength - randomLength -) - -// NewFakeClient creates a new fake client for testing. -// You can choose to initialize it with a slice of runtime.Object. -func NewFakeClient(initObjs ...runtime.Object) client.WithWatch { - return NewClientBuilder().WithRuntimeObjects(initObjs...).Build() -} - -// NewClientBuilder returns a new builder to create a fake client. -func NewClientBuilder() *ClientBuilder { - return &ClientBuilder{} -} - -// ClientBuilder builds a fake client. -type ClientBuilder struct { - scheme *runtime.Scheme - restMapper meta.RESTMapper - initObject []client.Object - initLists []client.ObjectList - initRuntimeObjects []runtime.Object - withStatusSubresource []client.Object - objectTracker testing.ObjectTracker - interceptorFuncs *interceptor.Funcs - - // indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK. - // The inner map maps from index name to IndexerFunc. - indexes map[schema.GroupVersionKind]map[string]client.IndexerFunc -} - -// WithScheme sets this builder's internal scheme. -// If not set, defaults to client-go's global scheme.Scheme. -func (f *ClientBuilder) WithScheme(scheme *runtime.Scheme) *ClientBuilder { - f.scheme = scheme - return f -} - -// WithRESTMapper sets this builder's restMapper. -// The restMapper is directly set as mapper in the Client. This can be used for example -// with a meta.DefaultRESTMapper to provide a static rest mapping. -// If not set, defaults to an empty meta.DefaultRESTMapper. -func (f *ClientBuilder) WithRESTMapper(restMapper meta.RESTMapper) *ClientBuilder { - f.restMapper = restMapper - return f -} - -// WithObjects can be optionally used to initialize this fake client with client.Object(s). -func (f *ClientBuilder) WithObjects(initObjs ...client.Object) *ClientBuilder { - f.initObject = append(f.initObject, initObjs...) - return f -} - -// WithLists can be optionally used to initialize this fake client with client.ObjectList(s). -func (f *ClientBuilder) WithLists(initLists ...client.ObjectList) *ClientBuilder { - f.initLists = append(f.initLists, initLists...) - return f -} - -// WithRuntimeObjects can be optionally used to initialize this fake client with runtime.Object(s). -func (f *ClientBuilder) WithRuntimeObjects(initRuntimeObjs ...runtime.Object) *ClientBuilder { - f.initRuntimeObjects = append(f.initRuntimeObjects, initRuntimeObjs...) - return f -} - -// WithObjectTracker can be optionally used to initialize this fake client with testing.ObjectTracker. -func (f *ClientBuilder) WithObjectTracker(ot testing.ObjectTracker) *ClientBuilder { - f.objectTracker = ot - return f -} - -// WithIndex can be optionally used to register an index with name `field` and indexer `extractValue` -// for API objects of the same GroupVersionKind (GVK) as `obj` in the fake client. -// It can be invoked multiple times, both with objects of the same GVK or different ones. -// Invoking WithIndex twice with the same `field` and GVK (via `obj`) arguments will panic. -// WithIndex retrieves the GVK of `obj` using the scheme registered via WithScheme if -// WithScheme was previously invoked, the default scheme otherwise. -func (f *ClientBuilder) WithIndex(obj runtime.Object, field string, extractValue client.IndexerFunc) *ClientBuilder { - objScheme := f.scheme - if objScheme == nil { - objScheme = scheme.Scheme - } - - gvk, err := apiutil.GVKForObject(obj, objScheme) - if err != nil { - panic(err) - } - - // If this is the first index being registered, we initialize the map storing all the indexes. - if f.indexes == nil { - f.indexes = make(map[schema.GroupVersionKind]map[string]client.IndexerFunc) - } - - // If this is the first index being registered for the GroupVersionKind of `obj`, we initialize - // the map storing the indexes for that GroupVersionKind. - if f.indexes[gvk] == nil { - f.indexes[gvk] = make(map[string]client.IndexerFunc) - } - - if _, fieldAlreadyIndexed := f.indexes[gvk][field]; fieldAlreadyIndexed { - panic(fmt.Errorf("indexer conflict: field %s for GroupVersionKind %v is already indexed", - field, gvk)) - } - - f.indexes[gvk][field] = extractValue - - return f -} - -// WithStatusSubresource configures the passed object with a status subresource, which means -// calls to Update and Patch will not alter its status. -func (f *ClientBuilder) WithStatusSubresource(o ...client.Object) *ClientBuilder { - f.withStatusSubresource = append(f.withStatusSubresource, o...) - return f -} - -// WithInterceptorFuncs configures the client methods to be intercepted using the provided interceptor.Funcs. -func (f *ClientBuilder) WithInterceptorFuncs(interceptorFuncs interceptor.Funcs) *ClientBuilder { - f.interceptorFuncs = &interceptorFuncs - return f -} - -// Build builds and returns a new fake client. -func (f *ClientBuilder) Build() client.WithWatch { - if f.scheme == nil { - f.scheme = scheme.Scheme - } - if f.restMapper == nil { - f.restMapper = meta.NewDefaultRESTMapper([]schema.GroupVersion{}) - } - - var tracker versionedTracker - - withStatusSubResource := sets.New(inTreeResourcesWithStatus()...) - for _, o := range f.withStatusSubresource { - gvk, err := apiutil.GVKForObject(o, f.scheme) - if err != nil { - panic(fmt.Errorf("failed to get gvk for object %T: %w", withStatusSubResource, err)) - } - withStatusSubResource.Insert(gvk) - } - - if f.objectTracker == nil { - tracker = versionedTracker{ObjectTracker: testing.NewObjectTracker(f.scheme, scheme.Codecs.UniversalDecoder()), scheme: f.scheme, withStatusSubresource: withStatusSubResource} - } else { - tracker = versionedTracker{ObjectTracker: f.objectTracker, scheme: f.scheme, withStatusSubresource: withStatusSubResource} - } - - for _, obj := range f.initObject { - if err := tracker.Add(obj); err != nil { - panic(fmt.Errorf("failed to add object %v to fake client: %w", obj, err)) - } - } - for _, obj := range f.initLists { - if err := tracker.Add(obj); err != nil { - panic(fmt.Errorf("failed to add list %v to fake client: %w", obj, err)) - } - } - for _, obj := range f.initRuntimeObjects { - if err := tracker.Add(obj); err != nil { - panic(fmt.Errorf("failed to add runtime object %v to fake client: %w", obj, err)) - } - } - - var result client.WithWatch = &fakeClient{ - tracker: tracker, - scheme: f.scheme, - restMapper: f.restMapper, - indexes: f.indexes, - withStatusSubresource: withStatusSubResource, - } - - if f.interceptorFuncs != nil { - result = interceptor.NewClient(result, *f.interceptorFuncs) - } - - return result -} - -const trackerAddResourceVersion = "999" - -func (t versionedTracker) Add(obj runtime.Object) error { - var objects []runtime.Object - if meta.IsListType(obj) { - var err error - objects, err = meta.ExtractList(obj) - if err != nil { - return err - } - } else { - objects = []runtime.Object{obj} - } - for _, obj := range objects { - accessor, err := meta.Accessor(obj) - if err != nil { - return fmt.Errorf("failed to get accessor for object: %w", err) - } - if accessor.GetDeletionTimestamp() != nil && len(accessor.GetFinalizers()) == 0 { - return fmt.Errorf("refusing to create obj %s with metadata.deletionTimestamp but no finalizers", accessor.GetName()) - } - if accessor.GetResourceVersion() == "" { - // We use a "magic" value of 999 here because this field - // is parsed as uint and and 0 is already used in Update. - // As we can't go lower, go very high instead so this can - // be recognized - accessor.SetResourceVersion(trackerAddResourceVersion) - } - - obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj) - if err != nil { - return err - } - if err := t.ObjectTracker.Add(obj); err != nil { - return err - } - } - - return nil -} - -func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error { - accessor, err := meta.Accessor(obj) - if err != nil { - return fmt.Errorf("failed to get accessor for object: %w", err) - } - if accessor.GetName() == "" { - return apierrors.NewInvalid( - obj.GetObjectKind().GroupVersionKind().GroupKind(), - accessor.GetName(), - field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")}) - } - if accessor.GetResourceVersion() != "" { - return apierrors.NewBadRequest("resourceVersion can not be set for Create requests") - } - accessor.SetResourceVersion("1") - obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj) - if err != nil { - return err - } - if err := t.ObjectTracker.Create(gvr, obj, ns); err != nil { - accessor.SetResourceVersion("") - return err - } - - return nil -} - -// convertFromUnstructuredIfNecessary will convert runtime.Unstructured for a GVK that is recognized -// by the schema into the whatever the schema produces with New() for said GVK. -// This is required because the tracker unconditionally saves on manipulations, but its List() implementation -// tries to assign whatever it finds into a ListType it gets from schema.New() - Thus we have to ensure -// we save as the very same type, otherwise subsequent List requests will fail. -func convertFromUnstructuredIfNecessary(s *runtime.Scheme, o runtime.Object) (runtime.Object, error) { - gvk := o.GetObjectKind().GroupVersionKind() - - u, isUnstructured := o.(runtime.Unstructured) - if !isUnstructured || !s.Recognizes(gvk) { - return o, nil - } - - typed, err := s.New(gvk) - if err != nil { - return nil, fmt.Errorf("scheme recognizes %s but failed to produce an object for it: %w", gvk, err) - } - - unstructuredSerialized, err := json.Marshal(u) - if err != nil { - return nil, fmt.Errorf("failed to serialize %T: %w", unstructuredSerialized, err) - } - if err := json.Unmarshal(unstructuredSerialized, typed); err != nil { - return nil, fmt.Errorf("failed to unmarshal the content of %T into %T: %w", u, typed, err) - } - - return typed, nil -} - -func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error { - isStatus := false - // We apply patches using a client-go reaction that ends up calling the trackers Update. As we can't change - // that reaction, we use the callstack to figure out if this originated from the status client. - if bytes.Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeSubResourceClient).statusPatch")) { - isStatus = true - } - return t.update(gvr, obj, ns, isStatus, false) -} - -func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, isStatus bool, deleting bool) error { - accessor, err := meta.Accessor(obj) - if err != nil { - return fmt.Errorf("failed to get accessor for object: %w", err) - } - - if accessor.GetName() == "" { - return apierrors.NewInvalid( - obj.GetObjectKind().GroupVersionKind().GroupKind(), - accessor.GetName(), - field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")}) - } - - gvk := obj.GetObjectKind().GroupVersionKind() - if gvk.Empty() { - gvk, err = apiutil.GVKForObject(obj, t.scheme) - if err != nil { - return err - } - } - - oldObject, err := t.ObjectTracker.Get(gvr, ns, accessor.GetName()) - if err != nil { - // If the resource is not found and the resource allows create on update, issue a - // create instead. - if apierrors.IsNotFound(err) && allowsCreateOnUpdate(gvk) { - return t.Create(gvr, obj, ns) - } - return err - } - - if t.withStatusSubresource.Has(gvk) { - if isStatus { // copy everything but status and metadata.ResourceVersion from original object - if err := copyStatusFrom(obj, oldObject); err != nil { - return fmt.Errorf("failed to copy non-status field for object with status subresouce: %w", err) - } - passedRV := accessor.GetResourceVersion() - if err := copyFrom(oldObject, obj); err != nil { - return fmt.Errorf("failed to restore non-status fields: %w", err) - } - accessor.SetResourceVersion(passedRV) - } else { // copy status from original object - if err := copyStatusFrom(oldObject, obj); err != nil { - return fmt.Errorf("failed to copy the status for object with status subresource: %w", err) - } - } - } else if isStatus { - return apierrors.NewNotFound(gvr.GroupResource(), accessor.GetName()) - } - - oldAccessor, err := meta.Accessor(oldObject) - if err != nil { - return err - } - - // If the new object does not have the resource version set and it allows unconditional update, - // default it to the resource version of the existing resource - if accessor.GetResourceVersion() == "" && allowsUnconditionalUpdate(gvk) { - accessor.SetResourceVersion(oldAccessor.GetResourceVersion()) - } - if accessor.GetResourceVersion() != oldAccessor.GetResourceVersion() { - return apierrors.NewConflict(gvr.GroupResource(), accessor.GetName(), errors.New("object was modified")) - } - if oldAccessor.GetResourceVersion() == "" { - oldAccessor.SetResourceVersion("0") - } - intResourceVersion, err := strconv.ParseUint(oldAccessor.GetResourceVersion(), 10, 64) - if err != nil { - return fmt.Errorf("can not convert resourceVersion %q to int: %w", oldAccessor.GetResourceVersion(), err) - } - intResourceVersion++ - accessor.SetResourceVersion(strconv.FormatUint(intResourceVersion, 10)) - - if !deleting && !deletionTimestampEqual(accessor, oldAccessor) { - return fmt.Errorf("error: Unable to edit %s: metadata.deletionTimestamp field is immutable", accessor.GetName()) - } - - if !accessor.GetDeletionTimestamp().IsZero() && len(accessor.GetFinalizers()) == 0 { - return t.ObjectTracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName()) - } - obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj) - if err != nil { - return err - } - return t.ObjectTracker.Update(gvr, obj, ns) -} - -func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - gvr, err := getGVRFromObject(obj, c.scheme) - if err != nil { - return err - } - o, err := c.tracker.Get(gvr, key.Namespace, key.Name) - if err != nil { - return err - } - - gvk, err := apiutil.GVKForObject(obj, c.scheme) - if err != nil { - return err - } - ta, err := meta.TypeAccessor(o) - if err != nil { - return err - } - ta.SetKind(gvk.Kind) - ta.SetAPIVersion(gvk.GroupVersion().String()) - - j, err := json.Marshal(o) - if err != nil { - return err - } - decoder := scheme.Codecs.UniversalDecoder() - zero(obj) - _, _, err = decoder.Decode(j, nil, obj) - return err -} - -func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...client.ListOption) (watch.Interface, error) { - gvk, err := apiutil.GVKForObject(list, c.scheme) - if err != nil { - return nil, err - } - - gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") - - listOpts := client.ListOptions{} - listOpts.ApplyOptions(opts) - - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - return c.tracker.Watch(gvr, listOpts.Namespace) -} - -func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error { - gvk, err := apiutil.GVKForObject(obj, c.scheme) - if err != nil { - return err - } - - originalKind := gvk.Kind - - gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") - - if _, isUnstructuredList := obj.(runtime.Unstructured); isUnstructuredList && !c.scheme.Recognizes(gvk) { - // We need to register the ListKind with UnstructuredList: - // https://github.com/kubernetes/kubernetes/blob/7b2776b89fb1be28d4e9203bdeec079be903c103/staging/src/k8s.io/client-go/dynamic/fake/simple.go#L44-L51 - c.schemeWriteLock.Lock() - c.scheme.AddKnownTypeWithName(gvk.GroupVersion().WithKind(gvk.Kind+"List"), &unstructured.UnstructuredList{}) - c.schemeWriteLock.Unlock() - } - - listOpts := client.ListOptions{} - listOpts.ApplyOptions(opts) - - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - o, err := c.tracker.List(gvr, gvk, listOpts.Namespace) - if err != nil { - return err - } - - ta, err := meta.TypeAccessor(o) - if err != nil { - return err - } - ta.SetKind(originalKind) - ta.SetAPIVersion(gvk.GroupVersion().String()) - - j, err := json.Marshal(o) - if err != nil { - return err - } - decoder := scheme.Codecs.UniversalDecoder() - zero(obj) - _, _, err = decoder.Decode(j, nil, obj) - if err != nil { - return err - } - - if listOpts.LabelSelector == nil && listOpts.FieldSelector == nil { - return nil - } - - // If we're here, either a label or field selector are specified (or both), so before we return - // the list we must filter it. If both selectors are set, they are ANDed. - objs, err := meta.ExtractList(obj) - if err != nil { - return err - } - - filteredList, err := c.filterList(objs, gvk, listOpts.LabelSelector, listOpts.FieldSelector) - if err != nil { - return err - } - - return meta.SetList(obj, filteredList) -} - -func (c *fakeClient) filterList(list []runtime.Object, gvk schema.GroupVersionKind, ls labels.Selector, fs fields.Selector) ([]runtime.Object, error) { - // Filter the objects with the label selector - filteredList := list - if ls != nil { - objsFilteredByLabel, err := objectutil.FilterWithLabels(list, ls) - if err != nil { - return nil, err - } - filteredList = objsFilteredByLabel - } - - // Filter the result of the previous pass with the field selector - if fs != nil { - objsFilteredByField, err := c.filterWithFields(filteredList, gvk, fs) - if err != nil { - return nil, err - } - filteredList = objsFilteredByField - } - - return filteredList, nil -} - -func (c *fakeClient) filterWithFields(list []runtime.Object, gvk schema.GroupVersionKind, fs fields.Selector) ([]runtime.Object, error) { - // We only allow filtering on the basis of a single field to ensure consistency with the - // behavior of the cache reader (which we're faking here). - fieldKey, fieldVal, requiresExact := selector.RequiresExactMatch(fs) - if !requiresExact { - return nil, fmt.Errorf("field selector %s is not in one of the two supported forms \"key==val\" or \"key=val\"", - fs) - } - - // Field selection is mimicked via indexes, so there's no sane answer this function can give - // if there are no indexes registered for the GroupVersionKind of the objects in the list. - indexes := c.indexes[gvk] - if len(indexes) == 0 || indexes[fieldKey] == nil { - return nil, fmt.Errorf("List on GroupVersionKind %v specifies selector on field %s, but no "+ - "index with name %s has been registered for GroupVersionKind %v", gvk, fieldKey, fieldKey, gvk) - } - - indexExtractor := indexes[fieldKey] - filteredList := make([]runtime.Object, 0, len(list)) - for _, obj := range list { - if c.objMatchesFieldSelector(obj, indexExtractor, fieldVal) { - filteredList = append(filteredList, obj) - } - } - return filteredList, nil -} - -func (c *fakeClient) objMatchesFieldSelector(o runtime.Object, extractIndex client.IndexerFunc, val string) bool { - obj, isClientObject := o.(client.Object) - if !isClientObject { - panic(fmt.Errorf("expected object %v to be of type client.Object, but it's not", o)) - } - - for _, extractedVal := range extractIndex(obj) { - if extractedVal == val { - return true - } - } - - return false -} - -func (c *fakeClient) Scheme() *runtime.Scheme { - return c.scheme -} - -func (c *fakeClient) RESTMapper() meta.RESTMapper { - return c.restMapper -} - -// GroupVersionKindFor returns the GroupVersionKind for the given object. -func (c *fakeClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { - return apiutil.GVKForObject(obj, c.scheme) -} - -// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced. -func (c *fakeClient) IsObjectNamespaced(obj runtime.Object) (bool, error) { - return apiutil.IsObjectNamespaced(obj, c.scheme, c.restMapper) -} - -func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - createOptions := &client.CreateOptions{} - createOptions.ApplyOptions(opts) - - for _, dryRunOpt := range createOptions.DryRun { - if dryRunOpt == metav1.DryRunAll { - return nil - } - } - - gvr, err := getGVRFromObject(obj, c.scheme) - if err != nil { - return err - } - accessor, err := meta.Accessor(obj) - if err != nil { - return err - } - - if accessor.GetName() == "" && accessor.GetGenerateName() != "" { - base := accessor.GetGenerateName() - if len(base) > maxGeneratedNameLength { - base = base[:maxGeneratedNameLength] - } - accessor.SetName(fmt.Sprintf("%s%s", base, utilrand.String(randomLength))) - } - // Ignore attempts to set deletion timestamp - if !accessor.GetDeletionTimestamp().IsZero() { - accessor.SetDeletionTimestamp(nil) - } - - return c.tracker.Create(gvr, obj, accessor.GetNamespace()) -} - -func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - gvr, err := getGVRFromObject(obj, c.scheme) - if err != nil { - return err - } - accessor, err := meta.Accessor(obj) - if err != nil { - return err - } - delOptions := client.DeleteOptions{} - delOptions.ApplyOptions(opts) - - for _, dryRunOpt := range delOptions.DryRun { - if dryRunOpt == metav1.DryRunAll { - return nil - } - } - - // Check the ResourceVersion if that Precondition was specified. - if delOptions.Preconditions != nil && delOptions.Preconditions.ResourceVersion != nil { - name := accessor.GetName() - dbObj, err := c.tracker.Get(gvr, accessor.GetNamespace(), name) - if err != nil { - return err - } - oldAccessor, err := meta.Accessor(dbObj) - if err != nil { - return err - } - actualRV := oldAccessor.GetResourceVersion() - expectRV := *delOptions.Preconditions.ResourceVersion - if actualRV != expectRV { - msg := fmt.Sprintf( - "the ResourceVersion in the precondition (%s) does not match the ResourceVersion in record (%s). "+ - "The object might have been modified", - expectRV, actualRV) - return apierrors.NewConflict(gvr.GroupResource(), name, errors.New(msg)) - } - } - - return c.deleteObject(gvr, accessor) -} - -func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { - gvk, err := apiutil.GVKForObject(obj, c.scheme) - if err != nil { - return err - } - - dcOptions := client.DeleteAllOfOptions{} - dcOptions.ApplyOptions(opts) - - for _, dryRunOpt := range dcOptions.DryRun { - if dryRunOpt == metav1.DryRunAll { - return nil - } - } - - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - o, err := c.tracker.List(gvr, gvk, dcOptions.Namespace) - if err != nil { - return err - } - - objs, err := meta.ExtractList(o) - if err != nil { - return err - } - filteredObjs, err := objectutil.FilterWithLabels(objs, dcOptions.LabelSelector) - if err != nil { - return err - } - for _, o := range filteredObjs { - accessor, err := meta.Accessor(o) - if err != nil { - return err - } - err = c.deleteObject(gvr, accessor) - if err != nil { - return err - } - } - return nil -} - -func (c *fakeClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - return c.update(obj, false, opts...) -} - -func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateOption) error { - updateOptions := &client.UpdateOptions{} - updateOptions.ApplyOptions(opts) - - for _, dryRunOpt := range updateOptions.DryRun { - if dryRunOpt == metav1.DryRunAll { - return nil - } - } - - gvr, err := getGVRFromObject(obj, c.scheme) - if err != nil { - return err - } - accessor, err := meta.Accessor(obj) - if err != nil { - return err - } - return c.tracker.update(gvr, obj, accessor.GetNamespace(), isStatus, false) -} - -func (c *fakeClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - return c.patch(obj, patch, opts...) -} - -func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - patchOptions := &client.PatchOptions{} - patchOptions.ApplyOptions(opts) - - for _, dryRunOpt := range patchOptions.DryRun { - if dryRunOpt == metav1.DryRunAll { - return nil - } - } - - gvr, err := getGVRFromObject(obj, c.scheme) - if err != nil { - return err - } - accessor, err := meta.Accessor(obj) - if err != nil { - return err - } - data, err := patch.Data(obj) - if err != nil { - return err - } - - gvk, err := apiutil.GVKForObject(obj, c.scheme) - if err != nil { - return err - } - - oldObj, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName()) - if err != nil { - return err - } - oldAccessor, err := meta.Accessor(oldObj) - if err != nil { - return err - } - - // Apply patch without updating object. - // To remain in accordance with the behavior of k8s api behavior, - // a patch must not allow for changes to the deletionTimestamp of an object. - // The reaction() function applies the patch to the object and calls Update(), - // whereas dryPatch() replicates this behavior but skips the call to Update(). - // This ensures that the patch may be rejected if a deletionTimestamp is modified, prior - // to updating the object. - action := testing.NewPatchAction(gvr, accessor.GetNamespace(), accessor.GetName(), patch.Type(), data) - o, err := dryPatch(action, c.tracker) - if err != nil { - return err - } - newObj, err := meta.Accessor(o) - if err != nil { - return err - } - - // Validate that deletionTimestamp has not been changed - if !deletionTimestampEqual(newObj, oldAccessor) { - return fmt.Errorf("rejected patch, metadata.deletionTimestamp immutable") - } - - reaction := testing.ObjectReaction(c.tracker) - handled, o, err := reaction(action) - if err != nil { - return err - } - if !handled { - panic("tracker could not handle patch method") - } - ta, err := meta.TypeAccessor(o) - if err != nil { - return err - } - ta.SetKind(gvk.Kind) - ta.SetAPIVersion(gvk.GroupVersion().String()) - - j, err := json.Marshal(o) - if err != nil { - return err - } - decoder := scheme.Codecs.UniversalDecoder() - zero(obj) - _, _, err = decoder.Decode(j, nil, obj) - return err -} - -// Applying a patch results in a deletionTimestamp that is truncated to the nearest second. -// Check that the diff between a new and old deletion timestamp is within a reasonable threshold -// to be considered unchanged. -func deletionTimestampEqual(newObj metav1.Object, obj metav1.Object) bool { - newTime := newObj.GetDeletionTimestamp() - oldTime := obj.GetDeletionTimestamp() - - if newTime == nil || oldTime == nil { - return newTime == oldTime - } - return newTime.Time.Sub(oldTime.Time).Abs() < time.Second -} - -// The behavior of applying the patch is pulled out into dryPatch(), -// which applies the patch and returns an object, but does not Update() the object. -// This function returns a patched runtime object that may then be validated before a call to Update() is executed. -// This results in some code duplication, but was found to be a cleaner alternative than unmarshalling and introspecting the patch data -// and easier than refactoring the k8s client-go method upstream. -// Duplicate of upstream: https://github.com/kubernetes/client-go/blob/783d0d33626e59d55d52bfd7696b775851f92107/testing/fixture.go#L146-L194 -func dryPatch(action testing.PatchActionImpl, tracker testing.ObjectTracker) (runtime.Object, error) { - ns := action.GetNamespace() - gvr := action.GetResource() - - obj, err := tracker.Get(gvr, ns, action.GetName()) - if err != nil { - return nil, err - } - - old, err := json.Marshal(obj) - if err != nil { - return nil, err - } - - // reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields - // in obj that are removed by patch are cleared - value := reflect.ValueOf(obj) - value.Elem().Set(reflect.New(value.Type().Elem()).Elem()) - - switch action.GetPatchType() { - case types.JSONPatchType: - patch, err := jsonpatch.DecodePatch(action.GetPatch()) - if err != nil { - return nil, err - } - modified, err := patch.Apply(old) - if err != nil { - return nil, err - } - - if err = json.Unmarshal(modified, obj); err != nil { - return nil, err - } - case types.MergePatchType: - modified, err := jsonpatch.MergePatch(old, action.GetPatch()) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(modified, obj); err != nil { - return nil, err - } - case types.StrategicMergePatchType, types.ApplyPatchType: - mergedByte, err := strategicpatch.StrategicMergePatch(old, action.GetPatch(), obj) - if err != nil { - return nil, err - } - if err = json.Unmarshal(mergedByte, obj); err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("PatchType is not supported") - } - return obj, nil -} - -// copyStatusFrom copies the status from old into new -func copyStatusFrom(old, new runtime.Object) error { - oldMapStringAny, err := toMapStringAny(old) - if err != nil { - return fmt.Errorf("failed to convert old to *unstructured.Unstructured: %w", err) - } - newMapStringAny, err := toMapStringAny(new) - if err != nil { - return fmt.Errorf("failed to convert new to *unststructured.Unstructured: %w", err) - } - - newMapStringAny["status"] = oldMapStringAny["status"] - - if err := fromMapStringAny(newMapStringAny, new); err != nil { - return fmt.Errorf("failed to convert back from map[string]any: %w", err) - } - - return nil -} - -// copyFrom copies from old into new -func copyFrom(old, new runtime.Object) error { - oldMapStringAny, err := toMapStringAny(old) - if err != nil { - return fmt.Errorf("failed to convert old to *unstructured.Unstructured: %w", err) - } - if err := fromMapStringAny(oldMapStringAny, new); err != nil { - return fmt.Errorf("failed to convert back from map[string]any: %w", err) - } - - return nil -} - -func toMapStringAny(obj runtime.Object) (map[string]any, error) { - if unstructured, isUnstructured := obj.(*unstructured.Unstructured); isUnstructured { - return unstructured.Object, nil - } - - serialized, err := json.Marshal(obj) - if err != nil { - return nil, err - } - - u := map[string]any{} - return u, json.Unmarshal(serialized, &u) -} - -func fromMapStringAny(u map[string]any, target runtime.Object) error { - if targetUnstructured, isUnstructured := target.(*unstructured.Unstructured); isUnstructured { - targetUnstructured.Object = u - return nil - } - - serialized, err := json.Marshal(u) - if err != nil { - return fmt.Errorf("failed to serialize: %w", err) - } - - zero(target) - if err := json.Unmarshal(serialized, &target); err != nil { - return fmt.Errorf("failed to deserialize: %w", err) - } - - return nil -} - -func (c *fakeClient) Status() client.SubResourceWriter { - return c.SubResource("status") -} - -func (c *fakeClient) SubResource(subResource string) client.SubResourceClient { - return &fakeSubResourceClient{client: c, subResource: subResource} -} - -func (c *fakeClient) deleteObject(gvr schema.GroupVersionResource, accessor metav1.Object) error { - old, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName()) - if err == nil { - oldAccessor, err := meta.Accessor(old) - if err == nil { - if len(oldAccessor.GetFinalizers()) > 0 { - now := metav1.Now() - oldAccessor.SetDeletionTimestamp(&now) - // Call update directly with mutability parameter set to true to allow - // changes to deletionTimestamp - return c.tracker.update(gvr, old, accessor.GetNamespace(), false, true) - } - } - } - - //TODO: implement propagation - return c.tracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName()) -} - -func getGVRFromObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionResource, error) { - gvk, err := apiutil.GVKForObject(obj, scheme) - if err != nil { - return schema.GroupVersionResource{}, err - } - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - return gvr, nil -} - -type fakeSubResourceClient struct { - client *fakeClient - subResource string -} - -func (sw *fakeSubResourceClient) Get(ctx context.Context, obj, subResource client.Object, opts ...client.SubResourceGetOption) error { - panic("fakeSubResourceClient does not support get") -} - -func (sw *fakeSubResourceClient) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error { - switch sw.subResource { - case "eviction": - _, isEviction := subResource.(*policyv1beta1.Eviction) - if !isEviction { - _, isEviction = subResource.(*policyv1.Eviction) - } - if !isEviction { - return apierrors.NewBadRequest(fmt.Sprintf("got invalid type %t, expected Eviction", subResource)) - } - if _, isPod := obj.(*corev1.Pod); !isPod { - return apierrors.NewNotFound(schema.GroupResource{}, "") - } - - return sw.client.Delete(ctx, obj) - default: - return fmt.Errorf("fakeSubResourceWriter does not support create for %s", sw.subResource) - } -} - -func (sw *fakeSubResourceClient) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - updateOptions := client.SubResourceUpdateOptions{} - updateOptions.ApplyOptions(opts) - - body := obj - if updateOptions.SubResourceBody != nil { - body = updateOptions.SubResourceBody - } - return sw.client.update(body, true, &updateOptions.UpdateOptions) -} - -func (sw *fakeSubResourceClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { - patchOptions := client.SubResourcePatchOptions{} - patchOptions.ApplyOptions(opts) - - body := obj - if patchOptions.SubResourceBody != nil { - body = patchOptions.SubResourceBody - } - - // this is necessary to identify that last call was made for status patch, through stack trace. - if sw.subResource == "status" { - return sw.statusPatch(body, patch, patchOptions) - } - - return sw.client.patch(body, patch, &patchOptions.PatchOptions) -} - -func (sw *fakeSubResourceClient) statusPatch(body client.Object, patch client.Patch, patchOptions client.SubResourcePatchOptions) error { - return sw.client.patch(body, patch, &patchOptions.PatchOptions) -} - -func allowsUnconditionalUpdate(gvk schema.GroupVersionKind) bool { - switch gvk.Group { - case "apps": - switch gvk.Kind { - case "ControllerRevision", "DaemonSet", "Deployment", "ReplicaSet", "StatefulSet": - return true - } - case "autoscaling": - switch gvk.Kind { - case "HorizontalPodAutoscaler": - return true - } - case "batch": - switch gvk.Kind { - case "CronJob", "Job": - return true - } - case "certificates": - switch gvk.Kind { - case "Certificates": - return true - } - case "flowcontrol": - switch gvk.Kind { - case "FlowSchema", "PriorityLevelConfiguration": - return true - } - case "networking": - switch gvk.Kind { - case "Ingress", "IngressClass", "NetworkPolicy": - return true - } - case "policy": - switch gvk.Kind { - case "PodSecurityPolicy": - return true - } - case "rbac.authorization.k8s.io": - switch gvk.Kind { - case "ClusterRole", "ClusterRoleBinding", "Role", "RoleBinding": - return true - } - case "scheduling": - switch gvk.Kind { - case "PriorityClass": - return true - } - case "settings": - switch gvk.Kind { - case "PodPreset": - return true - } - case "storage": - switch gvk.Kind { - case "StorageClass": - return true - } - case "": - switch gvk.Kind { - case "ConfigMap", "Endpoint", "Event", "LimitRange", "Namespace", "Node", - "PersistentVolume", "PersistentVolumeClaim", "Pod", "PodTemplate", - "ReplicationController", "ResourceQuota", "Secret", "Service", - "ServiceAccount", "EndpointSlice": - return true - } - } - - return false -} - -func allowsCreateOnUpdate(gvk schema.GroupVersionKind) bool { - switch gvk.Group { - case "coordination": - switch gvk.Kind { - case "Lease": - return true - } - case "node": - switch gvk.Kind { - case "RuntimeClass": - return true - } - case "rbac": - switch gvk.Kind { - case "ClusterRole", "ClusterRoleBinding", "Role", "RoleBinding": - return true - } - case "": - switch gvk.Kind { - case "Endpoint", "Event", "LimitRange", "Service": - return true - } - } - - return false -} - -func inTreeResourcesWithStatus() []schema.GroupVersionKind { - return []schema.GroupVersionKind{ - {Version: "v1", Kind: "Namespace"}, - {Version: "v1", Kind: "Node"}, - {Version: "v1", Kind: "PersistentVolumeClaim"}, - {Version: "v1", Kind: "PersistentVolume"}, - {Version: "v1", Kind: "Pod"}, - {Version: "v1", Kind: "ReplicationController"}, - {Version: "v1", Kind: "Service"}, - - {Group: "apps", Version: "v1", Kind: "Deployment"}, - {Group: "apps", Version: "v1", Kind: "DaemonSet"}, - {Group: "apps", Version: "v1", Kind: "ReplicaSet"}, - {Group: "apps", Version: "v1", Kind: "StatefulSet"}, - - {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}, - - {Group: "batch", Version: "v1", Kind: "CronJob"}, - {Group: "batch", Version: "v1", Kind: "Job"}, - - {Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"}, - - {Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"}, - {Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"}, - - {Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"}, - - {Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachment"}, - - {Group: "apiextensions.k8s.io", Version: "v1", Kind: "CustomResourceDefinition"}, - - {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "FlowSchema"}, - {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfiguration"}, - } -} - -// zero zeros the value of a pointer. -func zero(x interface{}) { - if x == nil { - return - } - res := reflect.ValueOf(x).Elem() - res.Set(reflect.Zero(res.Type())) -} diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go deleted file mode 100644 index d42347a2..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/* -Package fake provides a fake client for testing. - -A fake client is backed by its simple object store indexed by GroupVersionResource. -You can create a fake client with optional objects. - - client := NewClientBuilder().WithScheme(scheme).WithObj(initObjs...).Build() - -You can invoke the methods defined in the Client interface. - -When in doubt, it's almost always better not to use this package and instead use -envtest.Environment with a real client and API server. - -WARNING: ⚠️ Current Limitations / Known Issues with the fake Client ⚠️ - - This client does not have a way to inject specific errors to test handled vs. unhandled errors. - - There is some support for sub resources which can cause issues with tests if you're trying to update - e.g. metadata and status in the same reconcile. - - No OpenAPI validation is performed when creating or updating objects. - - ObjectMeta's `Generation` and `ResourceVersion` don't behave properly, Patch or Update - operations that rely on these fields will fail, or give false positives. -*/ -package fake diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept.go deleted file mode 100644 index 3d3f3cb0..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept.go +++ /dev/null @@ -1,166 +0,0 @@ -package interceptor - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/watch" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// Funcs contains functions that are called instead of the underlying client's methods. -type Funcs struct { - Get func(ctx context.Context, client client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error - List func(ctx context.Context, client client.WithWatch, list client.ObjectList, opts ...client.ListOption) error - Create func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.CreateOption) error - Delete func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteOption) error - DeleteAllOf func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteAllOfOption) error - Update func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.UpdateOption) error - Patch func(ctx context.Context, client client.WithWatch, obj client.Object, patch client.Patch, opts ...client.PatchOption) error - Watch func(ctx context.Context, client client.WithWatch, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error) - SubResource func(client client.WithWatch, subResource string) client.SubResourceClient - SubResourceGet func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, subResource client.Object, opts ...client.SubResourceGetOption) error - SubResourceCreate func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error - SubResourceUpdate func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, opts ...client.SubResourceUpdateOption) error - SubResourcePatch func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error -} - -// NewClient returns a new interceptor client that calls the functions in funcs instead of the underlying client's methods, if they are not nil. -func NewClient(interceptedClient client.WithWatch, funcs Funcs) client.WithWatch { - return interceptor{ - client: interceptedClient, - funcs: funcs, - } -} - -type interceptor struct { - client client.WithWatch - funcs Funcs -} - -var _ client.WithWatch = &interceptor{} - -func (c interceptor) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { - return c.client.GroupVersionKindFor(obj) -} - -func (c interceptor) IsObjectNamespaced(obj runtime.Object) (bool, error) { - return c.client.IsObjectNamespaced(obj) -} - -func (c interceptor) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - if c.funcs.Get != nil { - return c.funcs.Get(ctx, c.client, key, obj, opts...) - } - return c.client.Get(ctx, key, obj, opts...) -} - -func (c interceptor) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - if c.funcs.List != nil { - return c.funcs.List(ctx, c.client, list, opts...) - } - return c.client.List(ctx, list, opts...) -} - -func (c interceptor) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - if c.funcs.Create != nil { - return c.funcs.Create(ctx, c.client, obj, opts...) - } - return c.client.Create(ctx, obj, opts...) -} - -func (c interceptor) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - if c.funcs.Delete != nil { - return c.funcs.Delete(ctx, c.client, obj, opts...) - } - return c.client.Delete(ctx, obj, opts...) -} - -func (c interceptor) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - if c.funcs.Update != nil { - return c.funcs.Update(ctx, c.client, obj, opts...) - } - return c.client.Update(ctx, obj, opts...) -} - -func (c interceptor) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - if c.funcs.Patch != nil { - return c.funcs.Patch(ctx, c.client, obj, patch, opts...) - } - return c.client.Patch(ctx, obj, patch, opts...) -} - -func (c interceptor) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { - if c.funcs.DeleteAllOf != nil { - return c.funcs.DeleteAllOf(ctx, c.client, obj, opts...) - } - return c.client.DeleteAllOf(ctx, obj, opts...) -} - -func (c interceptor) Status() client.SubResourceWriter { - return c.SubResource("status") -} - -func (c interceptor) SubResource(subResource string) client.SubResourceClient { - if c.funcs.SubResource != nil { - return c.funcs.SubResource(c.client, subResource) - } - return subResourceInterceptor{ - subResourceName: subResource, - client: c.client, - funcs: c.funcs, - } -} - -func (c interceptor) Scheme() *runtime.Scheme { - return c.client.Scheme() -} - -func (c interceptor) RESTMapper() meta.RESTMapper { - return c.client.RESTMapper() -} - -func (c interceptor) Watch(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error) { - if c.funcs.Watch != nil { - return c.funcs.Watch(ctx, c.client, obj, opts...) - } - return c.client.Watch(ctx, obj, opts...) -} - -type subResourceInterceptor struct { - subResourceName string - client client.Client - funcs Funcs -} - -var _ client.SubResourceClient = &subResourceInterceptor{} - -func (s subResourceInterceptor) Get(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceGetOption) error { - if s.funcs.SubResourceGet != nil { - return s.funcs.SubResourceGet(ctx, s.client, s.subResourceName, obj, subResource, opts...) - } - return s.client.SubResource(s.subResourceName).Get(ctx, obj, subResource, opts...) -} - -func (s subResourceInterceptor) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error { - if s.funcs.SubResourceCreate != nil { - return s.funcs.SubResourceCreate(ctx, s.client, s.subResourceName, obj, subResource, opts...) - } - return s.client.SubResource(s.subResourceName).Create(ctx, obj, subResource, opts...) -} - -func (s subResourceInterceptor) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - if s.funcs.SubResourceUpdate != nil { - return s.funcs.SubResourceUpdate(ctx, s.client, s.subResourceName, obj, opts...) - } - return s.client.SubResource(s.subResourceName).Update(ctx, obj, opts...) -} - -func (s subResourceInterceptor) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { - if s.funcs.SubResourcePatch != nil { - return s.funcs.SubResourcePatch(ctx, s.client, s.subResourceName, obj, patch, opts...) - } - return s.client.SubResource(s.subResourceName).Patch(ctx, obj, patch, opts...) -} diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go deleted file mode 100644 index 91c5a3e3..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package controllertest contains fake informers for testing controllers -// When in doubt, it's almost always better to test against a real API server -// using envtest.Environment. -package controllertest diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go deleted file mode 100644 index 627915f9..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllertest - -import ( - "sync" - "time" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/util/workqueue" -) - -var _ runtime.Object = &ErrorType{} - -// ErrorType implements runtime.Object but isn't registered in any scheme and should cause errors in tests as a result. -type ErrorType struct{} - -// GetObjectKind implements runtime.Object. -func (ErrorType) GetObjectKind() schema.ObjectKind { return nil } - -// DeepCopyObject implements runtime.Object. -func (ErrorType) DeepCopyObject() runtime.Object { return nil } - -var _ workqueue.RateLimitingInterface = &Queue{} - -// Queue implements a RateLimiting queue as a non-ratelimited queue for testing. -// This helps testing by having functions that use a RateLimiting queue synchronously add items to the queue. -type Queue struct { - workqueue.Interface - AddedRateLimitedLock sync.Mutex - AddedRatelimited []any -} - -// AddAfter implements RateLimitingInterface. -func (q *Queue) AddAfter(item interface{}, duration time.Duration) { - q.Add(item) -} - -// AddRateLimited implements RateLimitingInterface. TODO(community): Implement this. -func (q *Queue) AddRateLimited(item interface{}) { - q.AddedRateLimitedLock.Lock() - q.AddedRatelimited = append(q.AddedRatelimited, item) - q.AddedRateLimitedLock.Unlock() - q.Add(item) -} - -// Forget implements RateLimitingInterface. TODO(community): Implement this. -func (q *Queue) Forget(item interface{}) {} - -// NumRequeues implements RateLimitingInterface. TODO(community): Implement this. -func (q *Queue) NumRequeues(item interface{}) int { - return 0 -} diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go deleted file mode 100644 index d0f50171..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllertest - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -var _ runtime.Object = &UnconventionalListType{} -var _ runtime.Object = &UnconventionalListTypeList{} - -// UnconventionalListType is used to test CRDs with List types that -// have a slice of pointers rather than a slice of literals. -type UnconventionalListType struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Spec string `json:"spec,omitempty"` -} - -// DeepCopyObject implements runtime.Object -// Handwritten for simplicity. -func (u *UnconventionalListType) DeepCopyObject() runtime.Object { - return u.DeepCopy() -} - -// DeepCopy implements *UnconventionalListType -// Handwritten for simplicity. -func (u *UnconventionalListType) DeepCopy() *UnconventionalListType { - return &UnconventionalListType{ - TypeMeta: u.TypeMeta, - ObjectMeta: *u.ObjectMeta.DeepCopy(), - Spec: u.Spec, - } -} - -// UnconventionalListTypeList is used to test CRDs with List types that -// have a slice of pointers rather than a slice of literals. -type UnconventionalListTypeList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []*UnconventionalListType `json:"items"` -} - -// DeepCopyObject implements runtime.Object -// Handwritten for simplicity. -func (u *UnconventionalListTypeList) DeepCopyObject() runtime.Object { - return u.DeepCopy() -} - -// DeepCopy implements *UnconventionalListTypeListt -// Handwritten for simplicity. -func (u *UnconventionalListTypeList) DeepCopy() *UnconventionalListTypeList { - out := &UnconventionalListTypeList{ - TypeMeta: u.TypeMeta, - ListMeta: *u.ListMeta.DeepCopy(), - } - for _, item := range u.Items { - out.Items = append(out.Items, item.DeepCopy()) - } - return out -} diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/util.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/util.go deleted file mode 100644 index 60ec61ed..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/util.go +++ /dev/null @@ -1,171 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllertest - -import ( - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" -) - -var _ cache.SharedIndexInformer = &FakeInformer{} - -// FakeInformer provides fake Informer functionality for testing. -type FakeInformer struct { - // Synced is returned by the HasSynced functions to implement the Informer interface - Synced bool - - // RunCount is incremented each time RunInformersAndControllers is called - RunCount int - - handlers []eventHandlerWrapper -} - -type modernResourceEventHandler interface { - OnAdd(obj interface{}, isInInitialList bool) - OnUpdate(oldObj, newObj interface{}) - OnDelete(obj interface{}) -} - -type legacyResourceEventHandler interface { - OnAdd(obj interface{}) - OnUpdate(oldObj, newObj interface{}) - OnDelete(obj interface{}) -} - -// eventHandlerWrapper wraps a ResourceEventHandler in a manner that is compatible with client-go 1.27+ and older. -// The interface was changed in these versions. -type eventHandlerWrapper struct { - handler any -} - -func (e eventHandlerWrapper) OnAdd(obj interface{}) { - if m, ok := e.handler.(modernResourceEventHandler); ok { - m.OnAdd(obj, false) - return - } - e.handler.(legacyResourceEventHandler).OnAdd(obj) -} - -func (e eventHandlerWrapper) OnUpdate(oldObj, newObj interface{}) { - if m, ok := e.handler.(modernResourceEventHandler); ok { - m.OnUpdate(oldObj, newObj) - return - } - e.handler.(legacyResourceEventHandler).OnUpdate(oldObj, newObj) -} - -func (e eventHandlerWrapper) OnDelete(obj interface{}) { - if m, ok := e.handler.(modernResourceEventHandler); ok { - m.OnDelete(obj) - return - } - e.handler.(legacyResourceEventHandler).OnDelete(obj) -} - -// AddIndexers does nothing. TODO(community): Implement this. -func (f *FakeInformer) AddIndexers(indexers cache.Indexers) error { - return nil -} - -// GetIndexer does nothing. TODO(community): Implement this. -func (f *FakeInformer) GetIndexer() cache.Indexer { - return nil -} - -// Informer returns the fake Informer. -func (f *FakeInformer) Informer() cache.SharedIndexInformer { - return f -} - -// HasSynced implements the Informer interface. Returns f.Synced. -func (f *FakeInformer) HasSynced() bool { - return f.Synced -} - -// AddEventHandler implements the Informer interface. Adds an EventHandler to the fake Informers. TODO(community): Implement Registration. -func (f *FakeInformer) AddEventHandler(handler cache.ResourceEventHandler) (cache.ResourceEventHandlerRegistration, error) { - f.handlers = append(f.handlers, eventHandlerWrapper{handler}) - return nil, nil -} - -// Run implements the Informer interface. Increments f.RunCount. -func (f *FakeInformer) Run(<-chan struct{}) { - f.RunCount++ -} - -// Add fakes an Add event for obj. -func (f *FakeInformer) Add(obj metav1.Object) { - for _, h := range f.handlers { - h.OnAdd(obj) - } -} - -// Update fakes an Update event for obj. -func (f *FakeInformer) Update(oldObj, newObj metav1.Object) { - for _, h := range f.handlers { - h.OnUpdate(oldObj, newObj) - } -} - -// Delete fakes an Delete event for obj. -func (f *FakeInformer) Delete(obj metav1.Object) { - for _, h := range f.handlers { - h.OnDelete(obj) - } -} - -// AddEventHandlerWithResyncPeriod does nothing. TODO(community): Implement this. -func (f *FakeInformer) AddEventHandlerWithResyncPeriod(handler cache.ResourceEventHandler, resyncPeriod time.Duration) (cache.ResourceEventHandlerRegistration, error) { - return nil, nil -} - -// RemoveEventHandler does nothing. TODO(community): Implement this. -func (f *FakeInformer) RemoveEventHandler(handle cache.ResourceEventHandlerRegistration) error { - return nil -} - -// GetStore does nothing. TODO(community): Implement this. -func (f *FakeInformer) GetStore() cache.Store { - return nil -} - -// GetController does nothing. TODO(community): Implement this. -func (f *FakeInformer) GetController() cache.Controller { - return nil -} - -// LastSyncResourceVersion does nothing. TODO(community): Implement this. -func (f *FakeInformer) LastSyncResourceVersion() string { - return "" -} - -// SetWatchErrorHandler does nothing. TODO(community): Implement this. -func (f *FakeInformer) SetWatchErrorHandler(cache.WatchErrorHandler) error { - return nil -} - -// SetTransform does nothing. TODO(community): Implement this. -func (f *FakeInformer) SetTransform(t cache.TransformFunc) error { - return nil -} - -// IsStopped does nothing. TODO(community): Implement this. -func (f *FakeInformer) IsStopped() bool { - return false -} diff --git a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go b/operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go deleted file mode 100644 index 0189c043..00000000 --- a/operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package objectutil - -import ( - apimeta "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" -) - -// FilterWithLabels returns a copy of the items in objs matching labelSel. -func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtime.Object, error) { - outItems := make([]runtime.Object, 0, len(objs)) - for _, obj := range objs { - meta, err := apimeta.Accessor(obj) - if err != nil { - return nil, err - } - if labelSel != nil { - lbls := labels.Set(meta.GetLabels()) - if !labelSel.Matches(lbls) { - continue - } - } - outItems = append(outItems, obj.DeepCopyObject()) - } - return outItems, nil -}