diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d3ea0a..d63227a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} cache: false # The golangci-lint action does its own caching. @@ -60,7 +60,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} @@ -116,9 +116,9 @@ jobs: run: ./crossplane xpkg build --package-file=${{ matrix.arch }}.xpkg --package-root=package/ --embed-runtime-image-tarball=runtime-${{ matrix.arch }}.tar - name: Upload Single-Platform Package - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: packages + name: package-${{ matrix.arch }} path: "*.xpkg" if-no-files-found: error retention-days: 1 @@ -135,18 +135,22 @@ jobs: uses: actions/checkout@v4 - name: Download Single-Platform Packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: packages path: . + merge-multiple: true - name: Setup the Crossplane CLI run: "curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh" - name: Login to Upbound + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3 if: env.XPKG_ACCESS_ID != '' - run: "./crossplane xpkg login -a borrelli-org -t ${{ secrets.XPKG_TOKEN }}" - + with: + registry: xpkg.upbound.io + username: ${{ secrets.XPKG_ACCESS_ID }} + password: ${{ secrets.XPKG_TOKEN }} + # If a version wasn't explicitly passed as a workflow_dispatch input we # default to version v0.0.0--, for example # v0.0.0-20231101115142-1091066df799. This is a simple implementation of diff --git a/.golangci.yml b/.golangci.yml index 5421bc0..33be29b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -38,7 +38,7 @@ linters-settings: - default - prefix(github.com/crossplane/crossplane-runtime) - prefix(github.com/crossplane/function-sdk-go) - - prefix(github.com/stevendborrelli/function-conditional-patch-and-transform) + - prefix(github.com/upboundcare/function-conditional-patch-and-transform) - blank - dot diff --git a/README.md b/README.md index 775cc79..dd21f92 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # function-conditional-patch-and-transform -[![CI](https://github.com/stevendborrelli/function-conditional-patch-and-transform/actions/workflows/ci.yml/badge.svg)](https://github.com/stevendborrelli/function-conditional-patch-and-transform/actions/workflows/ci.yml) ![GitHub release (latest SemVer)](https://img.shields.io/github/release/crossplane-contrib/function-conditional-patch-and-transform) +[![CI](https://github.com/upboundcare/function-conditional-patch-and-transform/actions/workflows/ci.yml/badge.svg)](https://github.com/upboundcare/function-conditional-patch-and-transform/actions/workflows/ci.yml) ![GitHub release (latest SemVer)](https://img.shields.io/github/release/crossplane-contrib/function-conditional-patch-and-transform) This composition function is a fork of the upstream [function-patch-and-transform](https://github.com/crossplane-contrib/function-patch-and-transform) that adds support for Conditional invocation of the function and the rendering @@ -18,7 +18,7 @@ metadata: annotations: render.crossplane.io/runtime: Development spec: - package: xpkg.upbound.io/borrelli-org/function-conditional-patch-and-transform:v0.4.0 + package: xpkg.upbound.io/upboundcare/function-conditional-patch-and-transform:v0.4.0 ``` ## What this function does @@ -240,9 +240,9 @@ $ crossplane xpkg build -f package --embed-runtime-image=runtime [docs-composition]: https://docs.crossplane.io/v1.14/getting-started/provider-aws-part-2/#create-a-deployment-template [docs-functions]: https://docs.crossplane.io/v1.14/concepts/composition-functions/ [docs-pandt]: https://docs.crossplane.io/v1.14/concepts/patch-and-transform/ -[fn-go-templating]: https://github.com/stevendborrelli/function-go-templating +[fn-go-templating]: https://github.com/upboundcare/function-go-templating [#4617]: https://github.com/crossplane/crossplane/issues/4617 [#4746]: https://github.com/crossplane/crossplane/issues/4746 [go]: https://go.dev [docker]: https://www.docker.com -[cli]: https://docs.crossplane.io/latest/cli \ No newline at end of file +[cli]: https://docs.crossplane.io/latest/cli diff --git a/condition_test.go b/condition_test.go index eefab03..cf13e09 100644 --- a/condition_test.go +++ b/condition_test.go @@ -12,7 +12,7 @@ import ( fnv1beta1 "github.com/crossplane/function-sdk-go/proto/v1beta1" "github.com/crossplane/function-sdk-go/resource" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) func TestEvaluateCondition(t *testing.T) { diff --git a/connection.go b/connection.go index 2a248b6..fddaf85 100644 --- a/connection.go +++ b/connection.go @@ -9,7 +9,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) // ConnectionDetailsExtractor extracts the connection details of a resource. diff --git a/connection_test.go b/connection_test.go index eafa683..4fa2fd6 100644 --- a/connection_test.go +++ b/connection_test.go @@ -14,7 +14,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/resource/fake" "github.com/crossplane/crossplane-runtime/pkg/test" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) func TestExtractConnectionDetails(t *testing.T) { diff --git a/examples/conditional-rendering/functions.yaml b/examples/conditional-rendering/functions.yaml index b197224..121ad68 100644 --- a/examples/conditional-rendering/functions.yaml +++ b/examples/conditional-rendering/functions.yaml @@ -3,5 +3,5 @@ kind: Function metadata: name: function-conditional-patch-and-transform spec: - package: xpkg.upbound.io/borrelli-org/function-conditional-patch-and-transform:v0.4.0 + package: xpkg.upbound.io/upboundcare/function-conditional-patch-and-transform:v0.4.0 packagePullPolicy: Always diff --git a/examples/conditional-resources/functions.yaml b/examples/conditional-resources/functions.yaml index b197224..121ad68 100644 --- a/examples/conditional-resources/functions.yaml +++ b/examples/conditional-resources/functions.yaml @@ -3,5 +3,5 @@ kind: Function metadata: name: function-conditional-patch-and-transform spec: - package: xpkg.upbound.io/borrelli-org/function-conditional-patch-and-transform:v0.4.0 + package: xpkg.upbound.io/upboundcare/function-conditional-patch-and-transform:v0.4.0 packagePullPolicy: Always diff --git a/fn.go b/fn.go index df01b37..2dc5ae1 100644 --- a/fn.go +++ b/fn.go @@ -5,8 +5,10 @@ import ( "google.golang.org/protobuf/types/known/structpb" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/json" "github.com/crossplane/crossplane-runtime/pkg/errors" + "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/logging" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" @@ -17,7 +19,7 @@ import ( "github.com/crossplane/function-sdk-go/resource/composed" "github.com/crossplane/function-sdk-go/response" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) const conditionError = "Condition error" @@ -131,10 +133,14 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1beta1.RunFunctionRe } if input.Environment != nil { - // Run all patches that are from the (observed) XR to the environment or from the environment to the (desired) XR. - if err := RenderEnvironmentPatches(env, oxr.Resource, dxr.Resource, input.Environment.Patches); err != nil { - response.Fatal(rsp, errors.Wrapf(err, "cannot render ToEnvironment patches from the composite resource")) - return rsp, nil + // Run all patches that are from the (observed) XR to the environment or + // from the environment to the (desired) XR. + for i := range input.Environment.Patches { + p := &input.Environment.Patches[i] + if err := ApplyEnvironmentPatch(p, env, oxr.Resource, dxr.Resource); err != nil { + response.Fatal(rsp, errors.Wrapf(err, "cannot apply the %q environment patch at index %d", p.GetType(), i)) + return rsp, nil + } } } @@ -181,14 +187,14 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1beta1.RunFunctionRe // We want to return this resource unmutated if rendering fails. dcd.Resource = cd.Resource.DeepCopy() default: - if err := RenderFromJSON(dcd.Resource, t.Base.Raw); err != nil { + if err := json.Unmarshal(t.Base.Raw, dcd.Resource); err != nil { response.Fatal(rsp, errors.Wrapf(err, "cannot parse base template of composed resource %q", t.Name)) return rsp, nil } } - ocd, ok := observed[resource.Name(t.Name)] - if ok { + ocd, exists := observed[resource.Name(t.Name)] + if exists { existing++ log.Debug("Resource template corresponds to existing composed resource", "metadata-name", ocd.Resource.GetName()) @@ -224,17 +230,56 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1beta1.RunFunctionRe "name", ocd.Resource.GetName()) } - errs, store := RenderComposedPatches(ocd.Resource, dcd.Resource, oxr.Resource, dxr.Resource, env, t.Patches) - for _, err := range errs { - response.Warning(rsp, errors.Wrapf(err, "cannot render patches for composed resource %q", t.Name)) - log.Info("Cannot render patches for composed resource", "warning", err) - warnings++ + // Run all patches that are to a desired composed resource, or from an + // observed composed resource. + skip := false + for i := range t.Patches { + p := &t.Patches[i] + if err := ApplyComposedPatch(p, ocd.Resource, dcd.Resource, oxr.Resource, dxr.Resource, env); err != nil { + if fieldpath.IsNotFound(err) { + // This is a patch from a required field path that does not + // exist. The point of FromFieldPathPolicyRequired is to + // block creation of the new 'to' resource until the 'from' + // field path exists. + // + // The only kind of resource we could be patching to that + // might not exist at this point is a composed resource. So + // if we're patching to a composed resource that doesn't + // exist we want to avoid creating it. Otherwise, we just + // treat the patch from a required field path the same way + // we'd treat a patch from an optional field path and skip + // it. + if p.GetPolicy().GetFromFieldPathPolicy() == v1beta1.FromFieldPathPolicyRequired { + if ToComposedResource(p) && !exists { + response.Warning(rsp, errors.Wrapf(err, "not adding new composed resource %q to desired state because %q patch at index %d has 'policy.fromFieldPath: Required'", t.Name, p.GetType(), i)) + + // There's no point processing further patches. + // They'll either be from an observed composed + // resource that doesn't exist yet, or to a desired + // composed resource that we'll discard. + skip = true + break + } + response.Warning(rsp, errors.Wrapf(err, "cannot render composed resource %q %q patch at index %d: ignoring 'policy.fromFieldPath: Required' because 'to' resource already exists", t.Name, p.GetType(), i)) + } + + // If any optional field path isn't found we just skip this + // patch and move on. The path may be populated by a + // subsequent patch. + continue + } + response.Fatal(rsp, errors.Wrapf(err, "cannot render composed resource %q %q patch at index %d", t.Name, p.GetType(), i)) + return rsp, nil + } } - if store { - // Add or replace our desired resource. - desired[resource.Name(t.Name)] = dcd + // Skip adding this resource to the desired state because it doesn't + // exist yet, and a required FromFieldPath was not (yet) found. + if skip { + continue } + + desired[resource.Name(t.Name)] = dcd } if err := response.SetDesiredCompositeResource(rsp, dxr); err != nil { diff --git a/fn_test.go b/fn_test.go index 6cac9cd..875f1ef 100644 --- a/fn_test.go +++ b/fn_test.go @@ -22,7 +22,7 @@ import ( "github.com/crossplane/function-sdk-go/resource" "github.com/crossplane/function-sdk-go/response" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) func TestRunFunction(t *testing.T) { @@ -384,17 +384,15 @@ func TestRunFunction(t *testing.T) { }, }, }, - "FailedPatchNotSaved": { - reason: "If we fail to patch a desired resource produced by a previous Function in the pipeline we should return a warning result, and leave the original desired resource untouched.", + "OptionalFieldPathNotFound": { + reason: "If we fail to patch a desired resource because an optional field path was not found we should skip the patch.", args: args{ req: &fnv1beta1.RunFunctionRequest{ Input: resource.MustStructObject(&v1beta1.Resources{ Resources: []v1beta1.ComposedTemplate{ { - // This template base no base, so we try to - // patch the resource named "cool-resource" in - // the desired resources array. Name: "cool-resource", + Base: &runtime.RawExtension{Raw: []byte(`{"apiVersion":"example.org/v1","kind":"CD","spec":{}}`)}, Patches: []v1beta1.ComposedPatch{ { // This patch should work. @@ -405,19 +403,11 @@ func TestRunFunction(t *testing.T) { }, }, { - // This patch should return an error, - // because the required path does not - // exist. + // This patch should be skipped, because + // the path is not found Type: v1beta1.PatchTypeFromCompositeFieldPath, Patch: v1beta1.Patch{ FromFieldPath: ptr.To[string]("spec.doesNotExist"), - ToFieldPath: ptr.To[string]("spec.explode"), - Policy: &v1beta1.PatchPolicy{ - FromFieldPath: func() *v1beta1.FromFieldPathPolicy { - r := v1beta1.FromFieldPathPolicyRequired - return &r - }(), - }, }, }, }, @@ -429,16 +419,105 @@ func TestRunFunction(t *testing.T) { Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), }, }, + }, + }, + want: want{ + rsp: &fnv1beta1.RunFunctionResponse{ + Meta: &fnv1beta1.ResponseMeta{Ttl: durationpb.New(response.DefaultTTL)}, Desired: &fnv1beta1.State{ Composite: &fnv1beta1.Resource{ - Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR"}`), }, Resources: map[string]*fnv1beta1.Resource{ "cool-resource": { - Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"watchers":42}}`), + // Watchers becomes "10" because our first patch + // worked. We only skipped the second patch. + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"watchers":"10"}}`), }, }, }, + Context: &structpb.Struct{Fields: map[string]*structpb.Value{fncontext.KeyEnvironment: structpb.NewStructValue(nil)}}, + }, + }, + }, + "RequiredFieldPathNotFound": { + reason: "If we fail to patch a desired resource because a required field path was not found, and the resource doesn't exist, we should not add it to desired state (i.e. create it).", + args: args{ + req: &fnv1beta1.RunFunctionRequest{ + Input: resource.MustStructObject(&v1beta1.Resources{ + Resources: []v1beta1.ComposedTemplate{ + { + Name: "new-resource", + Base: &runtime.RawExtension{Raw: []byte(`{"apiVersion":"example.org/v1","kind":"CD","spec":{}}`)}, + Patches: []v1beta1.ComposedPatch{ + { + // This patch will fail because the path + // is not found. + Type: v1beta1.PatchTypeFromCompositeFieldPath, + Patch: v1beta1.Patch{ + FromFieldPath: ptr.To[string]("spec.doesNotExist"), + Policy: &v1beta1.PatchPolicy{ + FromFieldPath: ptr.To[v1beta1.FromFieldPathPolicy](v1beta1.FromFieldPathPolicyRequired), + }, + }, + }, + }, + }, + { + Name: "existing-resource", + Base: &runtime.RawExtension{Raw: []byte(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"targetObject": {"keep": "me"}}}`)}, + Patches: []v1beta1.ComposedPatch{ + { + // This patch should work. + Type: v1beta1.PatchTypeFromCompositeFieldPath, + Patch: v1beta1.Patch{ + FromFieldPath: ptr.To[string]("spec.widgets"), + ToFieldPath: ptr.To[string]("spec.watchers"), + }, + }, + { + // This patch should work too and properly handle mergeOptions. + Type: v1beta1.PatchTypeFromCompositeFieldPath, + Patch: v1beta1.Patch{ + FromFieldPath: ptr.To[string]("spec.sourceObject"), + ToFieldPath: ptr.To[string]("spec.targetObject"), + Policy: &v1beta1.PatchPolicy{ + ToFieldPath: ptr.To(v1beta1.ToFieldPathPolicyMergeObject), + }, + }, + }, + { + // This patch will fail because the path + // is not found. + Type: v1beta1.PatchTypeFromCompositeFieldPath, + Patch: v1beta1.Patch{ + FromFieldPath: ptr.To[string]("spec.doesNotExist"), + Policy: &v1beta1.PatchPolicy{ + FromFieldPath: ptr.To[v1beta1.FromFieldPathPolicy](v1beta1.FromFieldPathPolicyRequired), + }, + }, + }, + }, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10", "sourceObject": {"me": "too"}}}`), + }, + Resources: map[string]*fnv1beta1.Resource{ + // "existing-resource" exists. + "existing-resource": {}, + + // Note "new-resource" doesn't appear in the + // observed resources. It doesn't yet exist. + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), + }, + }, }, }, want: want{ @@ -449,20 +528,85 @@ func TestRunFunction(t *testing.T) { Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), }, Resources: map[string]*fnv1beta1.Resource{ - "cool-resource": { - // spec.watchers would be "10" if we didn't - // discard the patch that worked. - Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"watchers":42}}`), + // Note that the first patch did work. We only + // skipped the patch from the required field path. + "existing-resource": { + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"watchers":"10", "targetObject": {"me": "too", "keep": "me"}}}`), }, + + // Note "new-resource" doesn't appear here. }, }, + Context: &structpb.Struct{Fields: map[string]*structpb.Value{fncontext.KeyEnvironment: structpb.NewStructValue(nil)}}, Results: []*fnv1beta1.Result{ { Severity: fnv1beta1.Severity_SEVERITY_WARNING, - Message: fmt.Sprintf("cannot render patches for composed resource %q: cannot apply the %q patch at index 1: spec.doesNotExist: no such field", "cool-resource", "FromCompositeFieldPath"), + Message: `not adding new composed resource "new-resource" to desired state because "FromCompositeFieldPath" patch at index 0 has 'policy.fromFieldPath: Required': spec.doesNotExist: no such field`, + }, + { + Severity: fnv1beta1.Severity_SEVERITY_WARNING, + Message: `cannot render composed resource "existing-resource" "FromCompositeFieldPath" patch at index 2: ignoring 'policy.fromFieldPath: Required' because 'to' resource already exists: spec.doesNotExist: no such field`, + }, + }, + }, + }, + }, + "PatchErrorIsFatal": { + reason: "If we fail to patch a desired resource we should return a fatal result.", + args: args{ + req: &fnv1beta1.RunFunctionRequest{ + Input: resource.MustStructObject(&v1beta1.Resources{ + Resources: []v1beta1.ComposedTemplate{ + { + Name: "cool-resource", + Base: &runtime.RawExtension{Raw: []byte(`{"apiVersion":"example.org/v1","kind":"CD","spec":{}}`)}, + Patches: []v1beta1.ComposedPatch{ + { + // This patch should work. + Type: v1beta1.PatchTypeFromCompositeFieldPath, + Patch: v1beta1.Patch{ + FromFieldPath: ptr.To[string]("spec.widgets"), + ToFieldPath: ptr.To[string]("spec.watchers"), + }, + }, + { + // This patch should return an error, + // because the path is not an array. + Type: v1beta1.PatchTypeFromCompositeFieldPath, + Patch: v1beta1.Patch{ + FromFieldPath: ptr.To[string]("spec.widgets[0]"), + }, + }, + }, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), + }, + }, + }, + }, + want: want{ + rsp: &fnv1beta1.RunFunctionResponse{ + Meta: &fnv1beta1.ResponseMeta{Ttl: durationpb.New(response.DefaultTTL)}, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"XR","spec":{"widgets":"10"}}`), + }, + }, + Results: []*fnv1beta1.Result{ + { + Severity: fnv1beta1.Severity_SEVERITY_FATAL, + Message: fmt.Sprintf("cannot render composed resource %q %q patch at index 1: spec.widgets: not an array", "cool-resource", "FromCompositeFieldPath"), }, }, - Context: &structpb.Struct{Fields: map[string]*structpb.Value{fncontext.KeyEnvironment: structpb.NewStructValue(nil)}}, }, }, }, @@ -658,9 +802,9 @@ func TestRunFunction(t *testing.T) { Environment: &v1beta1.Environment{ Patches: []v1beta1.EnvironmentPatch{ { - Type: v1beta1.PatchTypeFromEnvironmentFieldPath, + Type: v1beta1.PatchTypeToCompositeFieldPath, Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("data.widgets"), + FromFieldPath: ptr.To[string]("widgets"), ToFieldPath: ptr.To[string]("spec.watchers"), Transforms: []v1beta1.Transform{ { @@ -713,10 +857,10 @@ func TestRunFunction(t *testing.T) { Environment: &v1beta1.Environment{ Patches: []v1beta1.EnvironmentPatch{ { - Type: v1beta1.PatchTypeToEnvironmentFieldPath, + Type: v1beta1.PatchTypeFromCompositeFieldPath, Patch: v1beta1.Patch{ FromFieldPath: ptr.To[string]("spec.watchers"), - ToFieldPath: ptr.To[string]("data.widgets"), + ToFieldPath: ptr.To[string]("widgets"), Transforms: []v1beta1.Transform{ { Type: v1beta1.TransformTypeMath, @@ -764,7 +908,7 @@ func TestRunFunction(t *testing.T) { Patches: []v1beta1.ComposedPatch{{ Type: v1beta1.PatchTypeFromEnvironmentFieldPath, Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("data.widgets"), + FromFieldPath: ptr.To[string]("widgets"), ToFieldPath: ptr.To[string]("spec.watchers"), Transforms: []v1beta1.Transform{{ Type: v1beta1.TransformTypeConvert, @@ -816,7 +960,7 @@ func TestRunFunction(t *testing.T) { Patches: []v1beta1.ComposedPatch{{ Type: v1beta1.PatchTypeFromEnvironmentFieldPath, Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("data.widgets"), + FromFieldPath: ptr.To[string]("widgets"), ToFieldPath: ptr.To[string]("spec.watchers"), Transforms: []v1beta1.Transform{{ Type: v1beta1.TransformTypeConvert, @@ -872,7 +1016,7 @@ func TestRunFunction(t *testing.T) { Patches: []v1beta1.ComposedPatch{{ Type: v1beta1.PatchTypeFromEnvironmentFieldPath, Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("data.widgets"), + FromFieldPath: ptr.To[string]("widgets"), ToFieldPath: ptr.To[string]("spec.watchers"), Transforms: []v1beta1.Transform{{ Type: v1beta1.TransformTypeConvert, @@ -937,18 +1081,16 @@ func TestRunFunction(t *testing.T) { } // Crossplane sends as context a fake resource: -// { "apiVersion": "internal.crossplane.io/v1alpha1", "kind": "Environment", "data": {... the actual environment content ...} } +// { "apiVersion": "internal.crossplane.io/v1alpha1", "kind": "Environment", ... the actual environment content ... } // See: https://github.com/crossplane/crossplane/blob/806f0d20d146f6f4f1735c5ec6a7dc78923814b3/internal/controller/apiextensions/composite/environment_fetcher.go#L85C1-L85C1 // That's because the patching code expects a resource to be able to use // runtime.DefaultUnstructuredConverter.FromUnstructured to convert it back to -// an object. This is also why all patches need to specify the full path from data. +// an object. func contextWithEnvironment(data map[string]interface{}) *structpb.Struct { if data == nil { data = map[string]interface{}{} } - u := unstructured.Unstructured{Object: map[string]interface{}{ - "data": data, - }} + u := unstructured.Unstructured{Object: data} u.SetGroupVersionKind(schema.GroupVersionKind{Group: "internal.crossplane.io", Version: "v1alpha1", Kind: "Environment"}) d, err := structpb.NewStruct(u.UnstructuredContent()) if err != nil { diff --git a/go.mod b/go.mod index 40102c9..529a3ef 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/stevendborrelli/function-conditional-patch-and-transform +module github.com/upboundcare/function-conditional-patch-and-transform go 1.21 @@ -6,32 +6,33 @@ toolchain go1.21.3 require ( github.com/alecthomas/kong v0.8.1 - github.com/crossplane/crossplane-runtime v1.14.2 - github.com/crossplane/function-sdk-go v0.1.0 - github.com/google/cel-go v0.16.1 + github.com/crossplane/crossplane-runtime v1.15.1 + github.com/crossplane/function-sdk-go v0.2.0 + github.com/google/cel-go v0.19.0 github.com/google/go-cmp v0.6.0 github.com/pkg/errors v0.9.1 - google.golang.org/protobuf v1.31.0 - k8s.io/api v0.28.4 - k8s.io/apiextensions-apiserver v0.28.4 - k8s.io/apimachinery v0.28.4 - k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf - sigs.k8s.io/controller-tools v0.13.0 + google.golang.org/protobuf v1.32.0 + k8s.io/api v0.29.2 + k8s.io/apiextensions-apiserver v0.29.2 + k8s.io/apimachinery v0.29.2 + k8s.io/utils v0.0.0-20240102154912-e7106e64919e + sigs.k8s.io/controller-tools v0.14.0 ) require ( dario.cat/mergo v1.0.0 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/beorn7/perks v1.0.1 // indirect 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 v5.6.0 // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.8.0 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-json-experiment/json v0.0.0-20231013223334-54c864be5b8d // indirect - github.com/go-logr/logr v1.3.0 // indirect - github.com/go-logr/zapr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -41,50 +42,50 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect - github.com/spf13/afero v1.10.0 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.17.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/grpc v1.59.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/grpc v1.61.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.28.4 // indirect - k8s.io/component-base v0.28.4 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - sigs.k8s.io/controller-runtime v0.16.3 // indirect + k8s.io/client-go v0.29.2 // indirect + k8s.io/component-base v0.29.2 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + sigs.k8s.io/controller-runtime v0.17.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 1217ae5..614244e 100644 --- a/go.sum +++ b/go.sum @@ -1,48 +1,9 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0= +github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= github.com/alecthomas/kong v0.8.1 h1:acZdn3m4lLRobeh3Zi2S2EpnXTd1mOL6U7xVml+vfkY= github.com/alecthomas/kong v0.8.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= @@ -51,65 +12,44 @@ github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ4 github.com/antchfx/htmlquery v1.2.4/go.mod h1:2xO6iu3EVWs7R2JYqBbp8YzG50gj/ofqs5/0VZoDZLc= github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8= github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/crossplane/crossplane-runtime v1.14.1 h1:TCa7R1N4bDGHjsLhiRxR/mUhwmistlMACHm0kiiYKck= -github.com/crossplane/crossplane-runtime v1.14.1/go.mod h1:aOP+5W2wKpvthVs3pFNbVOe1jwrKYbJho0ThGNCVz9o= -github.com/crossplane/crossplane-runtime v1.14.2 h1:pV5JMzyzi/kcbeVBVPCat5MHH8zS94MBUapAyGx/Ry0= -github.com/crossplane/crossplane-runtime v1.14.2/go.mod h1:aOP+5W2wKpvthVs3pFNbVOe1jwrKYbJho0ThGNCVz9o= -github.com/crossplane/function-sdk-go v0.1.0 h1:WN3CUSaj6wgDqQPZZP1whMVIkTAZtN3HVCS67pTMzd8= -github.com/crossplane/function-sdk-go v0.1.0/go.mod h1:oRqHZ6RufpfZJ1N8aT4EfkP+5KpkhOKpWz7SeUDwwcw= -github.com/crossplane/upjet v0.11.0-rc.0.0.20231012093706-c4a76d2a7505 h1:eCmYgfRopVn6r8RM1Ra4XQAPwVsjTGfktBj2Dk7yy+Y= -github.com/crossplane/upjet v0.11.0-rc.0.0.20231012093706-c4a76d2a7505/go.mod h1:Ov+eoYS2n0Zge/E50zm65meOTYbAHnU6jPt27fQrpbc= +github.com/crossplane/crossplane-runtime v1.15.1 h1:g1h75tNYOQT152IUNxs8ZgSsRFQKrZN9z69KefMujXs= +github.com/crossplane/crossplane-runtime v1.15.1/go.mod h1:kRcJjJQmBFrR2n/KhwL8wYS7xNfq3D8eK4JliEScOHI= +github.com/crossplane/function-sdk-go v0.2.0 h1:4r+dXeGgwOC2XehJlHsHlkdkUsGW8PzkiyPPd2cshQs= +github.com/crossplane/function-sdk-go v0.2.0/go.mod h1:AvaWMHeKvzzE0vODLBrU5njOzW6sm61Ou4js9OdBUXM= +github.com/crossplane/upjet v1.1.0-rc.0.0.20231227120826-4cb45f9104ac h1:T1MTxsPAE/Cs0/EAGjeC29H9O/rO81yol2/5qGsf888= +github.com/crossplane/upjet v1.1.0-rc.0.0.20231227120826-4cb45f9104ac/go.mod h1:t9etxIdYaxgyvFPBToikm5zBHi8RIpX8N4mTH77lQFM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= +github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-json-experiment/json v0.0.0-20231013223334-54c864be5b8d h1:zqfo2jECgX5eYQseB/X+uV4Y5ocGOG/vG/LTztUCyPA= github.com/go-json-experiment/json v0.0.0-20231013223334-54c864be5b8d/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -122,51 +62,16 @@ github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo= -github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.19.0 h1:vVgaZoHPBDd1lXCYGQOh5A06L4EtuIfmqQ/qnSXSKiU= +github.com/google/cel-go v0.19.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -174,75 +79,48 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8= +github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw= -github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl/v2 v2.14.1 h1:x0BpjfZ+CYdbiz+8yZTQ+gdLO7IXvOut7Da+XJayx34= -github.com/hashicorp/hcl/v2 v2.14.1/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= +github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY= +github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= -github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= -github.com/hashicorp/terraform-plugin-go v0.14.0 h1:ttnSlS8bz3ZPYbMb84DpcPhY4F5DsQtcAS7cHo8uvP4= -github.com/hashicorp/terraform-plugin-go v0.14.0/go.mod h1:2nNCBeRLaenyQEi78xrGrs9hMbulveqG/zDMQSvVJTE= -github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs= -github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 h1:FtCLTiTcykdsURXPt/ku7fYXm3y19nbzbZcUxHx9RbI= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0/go.mod h1:80wf5oad1tW+oLnbXS4UTYmDCrl7BuN1Q+IA91X1a4Y= +github.com/hashicorp/terraform-json v0.17.0 h1:EiA1Wp07nknYQAiv+jIt4dX4Cq5crgP+TsTE45MjMmM= +github.com/hashicorp/terraform-json v0.17.0/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o= +github.com/hashicorp/terraform-plugin-go v0.16.0 h1:DSOQ0rz5FUiVO4NUzMs8ln9gsPgHMTsfns7Nk+6gPuE= +github.com/hashicorp/terraform-plugin-go v0.16.0/go.mod h1:4sn8bFuDbt+2+Yztt35IbOrvZc0zyEi87gJzsTgCES8= +github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= +github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.26.1 h1:G9WAfb8LHeCxu7Ae8nc1agZlQOSCUWsb610iAogBhCs= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.26.1/go.mod h1:xcOSYlRVdPLmDUoqPhO9fiO/YCN/l6MGYeTzGt5jgkQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -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= @@ -255,10 +133,10 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= @@ -280,46 +158,37 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= +github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +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.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= -github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 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/stevendborrelli/function-conditional-patch-and-transform v0.2.1 h1:8CNU6BGXWO+lqQw7t+calDuM9JEjQ61YYVA9fM9yv+8= -github.com/stevendborrelli/function-conditional-patch-and-transform v0.2.1/go.mod h1:B9hSlytx1BSH/zezwsRkLhcnEG1NHDQJE7Q5P4zxJGI= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -327,408 +196,137 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tmccombs/hcl2json v0.3.3 h1:+DLNYqpWE0CsOQiEZu+OZm5ZBImake3wtITYxQ8uLFQ= github.com/tmccombs/hcl2json v0.3.3/go.mod h1:Y2chtz2x9bAeRTvSibVRVgbLJhLJXKlUeIvjeVdnm4w= -github.com/upbound/provider-aws v0.43.0 h1:ycb6ybc1Dauy0DKiuXShbcjuh7GmPJRBjNngd5dluz8= -github.com/upbound/provider-aws v0.43.0/go.mod h1:m7hoCp3D469sk1vaRh8u4hC8SmpPBJO70JrZS9p2H/U= +github.com/upbound/provider-aws v0.47.1 h1:Z+eAy9Ut4suVrx79pkzhsYTC6uvxNW2jkwAQCUVbq3g= +github.com/upbound/provider-aws v0.47.1/go.mod h1:kYxEeLtZv1CJKbc+O1IribFA47Oqkuso3hSo5vdwptU= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= -github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= -github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= -github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0= -github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -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= +github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0= +github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apiextensions-apiserver v0.28.4 h1:AZpKY/7wQ8n+ZYDtNHbAJBb+N4AXXJvyZx6ww6yAJvU= -k8s.io/apiextensions-apiserver v0.28.4/go.mod h1:pgQIZ1U8eJSMQcENew/0ShUTlePcSGFq6dxSxf2mwPM= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= -k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= -k8s.io/component-base v0.28.4 h1:c/iQLWPdUgI90O+T9TeECg8o7N3YJTiuz2sKxILYcYo= -k8s.io/component-base v0.28.4/go.mod h1:m9hR0uvqXDybiGL2nf/3Lf0MerAfQXzkfWhUY58JUbU= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf h1:iTzha1p7Fi83476ypNSz8nV9iR9932jIIs26F7gNLsU= -k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= -sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= -sigs.k8s.io/controller-tools v0.13.0 h1:NfrvuZ4bxyolhDBt/rCZhDnx3M2hzlhgo5n3Iv2RykI= -sigs.k8s.io/controller-tools v0.13.0/go.mod h1:5vw3En2NazbejQGCeWKRrE7q4P+CW8/klfVqP8QZkgA= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apiextensions-apiserver v0.29.2 h1:UK3xB5lOWSnhaCk0RFZ0LUacPZz9RY4wi/yt2Iu+btg= +k8s.io/apiextensions-apiserver v0.29.2/go.mod h1:aLfYjpA5p3OwtqNXQFkhJ56TB+spV8Gc4wfMhUA3/b8= +k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= +k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= +k8s.io/component-base v0.29.2 h1:lpiLyuvPA9yV1aQwGLENYyK7n/8t6l3nn3zAtFTJYe8= +k8s.io/component-base v0.29.2/go.mod h1:BfB3SLrefbZXiBfbM+2H1dlat21Uewg/5qtKOl8degM= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.17.0 h1:fjJQf8Ukya+VjogLO6/bNX9HE6Y2xpsO5+fyS26ur/s= +sigs.k8s.io/controller-runtime v0.17.0/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= +sigs.k8s.io/controller-tools v0.14.0 h1:rnNoCC5wSXlrNoBKKzL70LNJKIQKEzT6lloG6/LF73A= +sigs.k8s.io/controller-tools v0.14.0/go.mod h1:TV7uOtNNnnR72SpzhStvPkoS/U5ir0nMudrkrC4M9Sc= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/input/v1beta1/resources.go b/input/v1beta1/resources.go index a943aaa..a06c61d 100644 --- a/input/v1beta1/resources.go +++ b/input/v1beta1/resources.go @@ -20,7 +20,7 @@ type Resources struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - // If defines a CEL condition whether this function will render + // Condition defines a CEL condition whether this function will render Condition Condition `json:"condition,omitempty"` // PatchSets define a named set of patches that may be included by any diff --git a/input/v1beta1/resources_patches.go b/input/v1beta1/resources_patches.go index 9478a79..eefb40d 100644 --- a/input/v1beta1/resources_patches.go +++ b/input/v1beta1/resources_patches.go @@ -32,15 +32,34 @@ const ( FromFieldPathPolicyRequired FromFieldPathPolicy = "Required" ) +// A ToFieldPathPolicy determines how to patch to a field path. +type ToFieldPathPolicy string + +// ToFieldPath patch policies. +const ( + ToFieldPathPolicyReplace ToFieldPathPolicy = "Replace" + ToFieldPathPolicyMergeObject ToFieldPathPolicy = "MergeObject" + ToFieldPathPolicyAppendArray ToFieldPathPolicy = "AppendArray" +) + // A PatchPolicy configures the specifics of patching behaviour. type PatchPolicy struct { // FromFieldPath specifies how to patch from a field path. The default is // 'Optional', which means the patch will be a no-op if the specified - // fromFieldPath does not exist. Use 'Required' if the patch should fail if - // the specified path does not exist. + // fromFieldPath does not exist. Use 'Required' to prevent the creation of a + // new composed resource until the required path exists. // +kubebuilder:validation:Enum=Optional;Required // +optional FromFieldPath *FromFieldPathPolicy `json:"fromFieldPath,omitempty"` + + // ToFieldPath specifies how to patch to a field path. The default is + // 'Replace', which means the patch will completely replace the target field, + // or create it if it does not exist. Use 'MergeObject' to merge the patch + // object with the target object, or 'AppendArray' to append the patch array + // to the target array. + // +kubebuilder:validation:Enum=Replace;MergeObject;AppendArray + // +optional + ToFieldPath *ToFieldPathPolicy `json:"toFieldPath,omitempty"` } // GetFromFieldPathPolicy returns the FromFieldPathPolicy for this PatchPolicy, defaulting to FromFieldPathPolicyOptional if not specified. @@ -51,6 +70,14 @@ func (pp *PatchPolicy) GetFromFieldPathPolicy() FromFieldPathPolicy { return *pp.FromFieldPath } +// GetToFieldPathPolicy returns the ToFieldPathPolicy for this PatchPolicy, defaulting to ToFieldPathPolicyReplace if not specified. +func (pp *PatchPolicy) GetToFieldPathPolicy() ToFieldPathPolicy { + if pp == nil || pp.ToFieldPath == nil { + return ToFieldPathPolicyReplace + } + return *pp.ToFieldPath +} + // Environment represents the Composition environment. type Environment struct { // Patches is a list of environment patches that are executed before a diff --git a/input/v1beta1/zz_generated.deepcopy.go b/input/v1beta1/zz_generated.deepcopy.go index fcc56b2..99aba00 100644 --- a/input/v1beta1/zz_generated.deepcopy.go +++ b/input/v1beta1/zz_generated.deepcopy.go @@ -370,6 +370,11 @@ func (in *PatchPolicy) DeepCopyInto(out *PatchPolicy) { *out = new(FromFieldPathPolicy) **out = **in } + if in.ToFieldPath != nil { + in, out := &in.ToFieldPath, &out.ToFieldPath + *out = new(ToFieldPathPolicy) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PatchPolicy. diff --git a/package/crossplane.yaml b/package/crossplane.yaml index 48215e0..5df4b7a 100644 --- a/package/crossplane.yaml +++ b/package/crossplane.yaml @@ -5,7 +5,7 @@ metadata: name: function-conditional-patch-and-transform annotations: meta.crossplane.io/maintainer: Crossplane Maintainers - meta.crossplane.io/source: github.com/stevendborrelli/function-conditional-patch-and-transform + meta.crossplane.io/source: github.com/upboundcare/function-conditional-patch-and-transform meta.crossplane.io/license: Apache-2.0 meta.crossplane.io/description: A patch & transform composition function that supports conditionals meta.crossplane.io/readme: | @@ -13,6 +13,6 @@ metadata: that adds support for Conditional invocation of the function and the rendering of individual resources. See the - [README](https://github.com/stevendborrelli/function-conditional-patch-and-transform) + [README](https://github.com/upboundcare/function-conditional-patch-and-transform) for examples and documentation. spec: {} diff --git a/package/input/conditional-pt.fn.crossplane.io_resources.yaml b/package/input/conditional-pt.fn.crossplane.io_resources.yaml index a805c0c..b5d234c 100644 --- a/package/input/conditional-pt.fn.crossplane.io_resources.yaml +++ b/package/input/conditional-pt.fn.crossplane.io_resources.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: resources.conditional-pt.fn.crossplane.io spec: group: conditional-pt.fn.crossplane.io @@ -22,64 +22,76 @@ spec: description: Resources specifies Patch & Transform resource templates. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string condition: - description: If defines a CEL condition whether this function will render + description: Condition defines a CEL condition whether this function will + render type: string environment: - description: "Environment represents the Composition environment. \n THIS - IS AN ALPHA FIELD. Do not use it in production. It may be changed or - removed without notice." + description: |- + Environment represents the Composition environment. + + + THIS IS AN ALPHA FIELD. + Do not use it in production. It may be changed or removed without notice. properties: patches: - description: Patches is a list of environment patches that are executed - before a composition's resources are composed. These patches are - between the XR and the Environment. Either from the Environment - to the XR, or vice versa. + description: |- + Patches is a list of environment patches that are executed before a + composition's resources are composed. These patches are between the XR + and the Environment. Either from the Environment to the XR, or vice + versa. items: - description: EnvironmentPatch objects are applied between the composite - resource and the environment. Their behaviour depends on the Type - selected. The default Type, FromCompositeFieldPath, copies a value - from the composite resource to the environment, applying any defined - transformers. + description: |- + EnvironmentPatch objects are applied between the composite resource and + the environment. Their behaviour depends on the Type selected. The default + Type, FromCompositeFieldPath, copies a value from the composite resource + to the environment, applying any defined transformers. properties: combine: - description: Combine is the patch configuration for a CombineFromComposite, + description: |- + Combine is the patch configuration for a CombineFromComposite, CombineToComposite patch. properties: strategy: - description: Strategy defines the strategy to use to combine - the input variable values. Currently only string is supported. + description: |- + Strategy defines the strategy to use to combine the input variable values. + Currently only string is supported. enum: - string type: string string: - description: String declares that input variables should - be combined into a single string, using the relevant settings - for formatting purposes. + description: |- + String declares that input variables should be combined into a single + string, using the relevant settings for formatting purposes. properties: fmt: - description: Format the input using a Go format string. - See https://golang.org/pkg/fmt/ for details. + description: |- + Format the input using a Go format string. See + https://golang.org/pkg/fmt/ for details. type: string required: - fmt type: object variables: - description: Variables are the list of variables whose values - will be retrieved and combined. + description: |- + Variables are the list of variables whose values will be retrieved and + combined. items: - description: A CombineVariable defines the source of a - value that is combined with others to form and patch - an output value. Currently, this only supports retrieving - values from a field path. + description: |- + A CombineVariable defines the source of a value that is combined with + others to form and patch an output value. Currently, this only supports + retrieving values from a field path. properties: fromFieldPath: - description: FromFieldPath is the path of the field - on the source whose value is to be used as input. + description: |- + FromFieldPath is the path of the field on the source whose value is + to be used as input. type: string required: - fromFieldPath @@ -91,49 +103,68 @@ spec: - variables type: object fromFieldPath: - description: FromFieldPath is the path of the field on the resource - whose value is to be used as input. Required when type is - FromCompositeFieldPath or ToCompositeFieldPath. + description: |- + FromFieldPath is the path of the field on the resource whose value is + to be used as input. Required when type is FromCompositeFieldPath or + ToCompositeFieldPath. type: string policy: description: Policy configures the specifics of patching behaviour. properties: fromFieldPath: - description: FromFieldPath specifies how to patch from a - field path. The default is 'Optional', which means the - patch will be a no-op if the specified fromFieldPath does - not exist. Use 'Required' if the patch should fail if - the specified path does not exist. + description: |- + FromFieldPath specifies how to patch from a field path. The default is + 'Optional', which means the patch will be a no-op if the specified + fromFieldPath does not exist. Use 'Required' to prevent the creation of a + new composed resource until the required path exists. enum: - Optional - Required type: string + toFieldPath: + description: |- + ToFieldPath specifies how to patch to a field path. The default is + 'Replace', which means the patch will completely replace the target field, + or create it if it does not exist. Use 'MergeObject' to merge the patch + object with the target object, or 'AppendArray' to append the patch array + to the target array. + enum: + - Replace + - MergeObject + - AppendArray + type: string type: object toFieldPath: - description: ToFieldPath is the path of the field on the resource - whose value will be changed with the result of transforms. - Leave empty if you'd like to propagate to the same path as - fromFieldPath. + description: |- + ToFieldPath is the path of the field on the resource whose value will + be changed with the result of transforms. Leave empty if you'd like to + propagate to the same path as fromFieldPath. type: string transforms: - description: Transforms are the list of functions that are used - as a FIFO pipe for the input to be transformed. + description: |- + Transforms are the list of functions that are used as a FIFO pipe for the + input to be transformed. items: - description: Transform is a unit of process whose input is - transformed into an output with the supplied configuration. + description: |- + Transform is a unit of process whose input is transformed into an output with + the supplied configuration. properties: convert: description: Convert is used to cast the input into the given output type. properties: format: - description: "The expected input format. \n * `quantity` - - parses the input as a K8s [`resource.Quantity`](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity). + description: |- + The expected input format. + + + * `quantity` - parses the input as a K8s [`resource.Quantity`](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity). Only used during `string -> float64` conversions. - * `json` - parses the input as a JSON string. Only - used during `string -> object` or `string -> list` - conversions. \n If this property is null, the default - conversion is applied." + * `json` - parses the input as a JSON string. + Only used during `string -> object` or `string -> list` conversions. + + + If this property is null, the default conversion is applied. enum: - none - quantity @@ -173,26 +204,29 @@ spec: - Input type: string fallbackValue: - description: The fallback value that should be returned - by the transform if now pattern matches. + description: |- + The fallback value that should be returned by the transform if now pattern + matches. x-kubernetes-preserve-unknown-fields: true patterns: - description: The patterns that should be tested against - the input string. Patterns are tested in order. - The value of the first match is used as result of - this transform. + description: |- + The patterns that should be tested against the input string. + Patterns are tested in order. The value of the first match is used as + result of this transform. items: - description: MatchTransformPattern is a transform - that returns the value that matches a pattern. + description: |- + MatchTransformPattern is a transform that returns the value that matches a + pattern. properties: literal: - description: Literal exactly matches the input - string (case sensitive). Is required if `type` - is `literal`. + description: |- + Literal exactly matches the input string (case sensitive). + Is required if `type` is `literal`. type: string regexp: - description: Regexp to match against the input - string. Is required if `type` is `regexp`. + description: |- + Regexp to match against the input string. + Is required if `type` is `regexp`. type: string result: description: The value that is used as result @@ -200,14 +234,17 @@ spec: x-kubernetes-preserve-unknown-fields: true type: default: literal - description: "Type specifies how the pattern - matches the input. \n * `literal` - the pattern - value has to exactly match (case sensitive) - the input string. This is the default. \n - * `regexp` - the pattern treated as a regular - expression against which the input string - is tested. Crossplane will throw an error - if the key is not a valid regexp." + description: |- + Type specifies how the pattern matches the input. + + + * `literal` - the pattern value has to exactly match (case sensitive) the + input string. This is the default. + + + * `regexp` - the pattern treated as a regular expression against + which the input string is tested. Crossplane will throw an error if the + key is not a valid regexp. enum: - literal - regexp @@ -219,8 +256,9 @@ spec: type: array type: object math: - description: Math is used to transform the input via mathematical - operations such as multiplication. + description: |- + Math is used to transform the input via mathematical operations such as + multiplication. properties: clampMax: description: ClampMax makes sure that the value is @@ -246,18 +284,18 @@ spec: type: string type: object string: - description: String is used to transform the input into - a string or a different kind of string. Note that the - input does not necessarily need to be a string. + description: |- + String is used to transform the input into a string or a different kind + of string. Note that the input does not necessarily need to be a string. properties: convert: - description: Optional conversion method to be specified. - `ToUpper` and `ToLower` change the letter case of - the input string. `ToBase64` and `FromBase64` perform - a base64 conversion based on the input string. `ToJson` - converts any input value into its raw JSON representation. - `ToSha1`, `ToSha256` and `ToSha512` generate a hash - value based on the input converted to JSON. + description: |- + Optional conversion method to be specified. + `ToUpper` and `ToLower` change the letter case of the input string. + `ToBase64` and `FromBase64` perform a base64 conversion based on the input string. + `ToJson` converts any input value into its raw JSON representation. + `ToSha1`, `ToSha256` and `ToSha512` generate a hash value based on the input + converted to JSON. enum: - ToUpper - ToLower @@ -269,8 +307,9 @@ spec: - ToSha512 type: string fmt: - description: Format the input using a Go format string. - See https://golang.org/pkg/fmt/ for details. + description: |- + Format the input using a Go format string. See + https://golang.org/pkg/fmt/ for details. type: string regexp: description: Extract a match from the input using @@ -281,9 +320,9 @@ spec: matches the entire expression. type: integer match: - description: Match string. May optionally include - submatches, aka capture groups. See https://pkg.go.dev/regexp/ - for details. + description: |- + Match string. May optionally include submatches, aka capture groups. + See https://pkg.go.dev/regexp/ for details. type: string required: - match @@ -317,9 +356,9 @@ spec: type: array type: default: FromCompositeFieldPath - description: Type sets the patching behaviour to be used. Each - patch type may require its own fields to be set on the Patch - object. + description: |- + Type sets the patching behaviour to be used. Each patch type may require + its own fields to be set on the Patch object. enum: - FromCompositeFieldPath - ToCompositeFieldPath @@ -330,15 +369,19 @@ spec: type: array type: object kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object patchSets: - description: PatchSets define a named set of patches that may be included - by any resource. PatchSets cannot themselves refer to other PatchSets. + description: |- + PatchSets define a named set of patches that may be included by any + resource. PatchSets cannot themselves refer to other PatchSets. items: description: A PatchSet is a set of patches that can be reused from all resources. @@ -349,44 +392,49 @@ spec: patches: description: Patches will be applied as an overlay to the base resource. items: - description: PatchSetPatch defines a set of Patches that can be - referenced by name by other patches of type PatchSet. + description: |- + PatchSetPatch defines a set of Patches that can be referenced by name by + other patches of type PatchSet. properties: combine: - description: Combine is the patch configuration for a CombineFromComposite, + description: |- + Combine is the patch configuration for a CombineFromComposite, CombineToComposite patch. properties: strategy: - description: Strategy defines the strategy to use to combine - the input variable values. Currently only string is - supported. + description: |- + Strategy defines the strategy to use to combine the input variable values. + Currently only string is supported. enum: - string type: string string: - description: String declares that input variables should - be combined into a single string, using the relevant - settings for formatting purposes. + description: |- + String declares that input variables should be combined into a single + string, using the relevant settings for formatting purposes. properties: fmt: - description: Format the input using a Go format string. - See https://golang.org/pkg/fmt/ for details. + description: |- + Format the input using a Go format string. See + https://golang.org/pkg/fmt/ for details. type: string required: - fmt type: object variables: - description: Variables are the list of variables whose - values will be retrieved and combined. + description: |- + Variables are the list of variables whose values will be retrieved and + combined. items: - description: A CombineVariable defines the source of - a value that is combined with others to form and patch - an output value. Currently, this only supports retrieving - values from a field path. + description: |- + A CombineVariable defines the source of a value that is combined with + others to form and patch an output value. Currently, this only supports + retrieving values from a field path. properties: fromFieldPath: - description: FromFieldPath is the path of the field - on the source whose value is to be used as input. + description: |- + FromFieldPath is the path of the field on the source whose value is + to be used as input. type: string required: - fromFieldPath @@ -398,49 +446,68 @@ spec: - variables type: object fromFieldPath: - description: FromFieldPath is the path of the field on the - resource whose value is to be used as input. Required when - type is FromCompositeFieldPath or ToCompositeFieldPath. + description: |- + FromFieldPath is the path of the field on the resource whose value is + to be used as input. Required when type is FromCompositeFieldPath or + ToCompositeFieldPath. type: string policy: description: Policy configures the specifics of patching behaviour. properties: fromFieldPath: - description: FromFieldPath specifies how to patch from - a field path. The default is 'Optional', which means - the patch will be a no-op if the specified fromFieldPath - does not exist. Use 'Required' if the patch should fail - if the specified path does not exist. + description: |- + FromFieldPath specifies how to patch from a field path. The default is + 'Optional', which means the patch will be a no-op if the specified + fromFieldPath does not exist. Use 'Required' to prevent the creation of a + new composed resource until the required path exists. enum: - Optional - Required type: string + toFieldPath: + description: |- + ToFieldPath specifies how to patch to a field path. The default is + 'Replace', which means the patch will completely replace the target field, + or create it if it does not exist. Use 'MergeObject' to merge the patch + object with the target object, or 'AppendArray' to append the patch array + to the target array. + enum: + - Replace + - MergeObject + - AppendArray + type: string type: object toFieldPath: - description: ToFieldPath is the path of the field on the resource - whose value will be changed with the result of transforms. - Leave empty if you'd like to propagate to the same path - as fromFieldPath. + description: |- + ToFieldPath is the path of the field on the resource whose value will + be changed with the result of transforms. Leave empty if you'd like to + propagate to the same path as fromFieldPath. type: string transforms: - description: Transforms are the list of functions that are - used as a FIFO pipe for the input to be transformed. + description: |- + Transforms are the list of functions that are used as a FIFO pipe for the + input to be transformed. items: - description: Transform is a unit of process whose input - is transformed into an output with the supplied configuration. + description: |- + Transform is a unit of process whose input is transformed into an output with + the supplied configuration. properties: convert: description: Convert is used to cast the input into the given output type. properties: format: - description: "The expected input format. \n * `quantity` - - parses the input as a K8s [`resource.Quantity`](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity). + description: |- + The expected input format. + + + * `quantity` - parses the input as a K8s [`resource.Quantity`](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity). Only used during `string -> float64` conversions. * `json` - parses the input as a JSON string. - Only used during `string -> object` or `string - -> list` conversions. \n If this property is null, - the default conversion is applied." + Only used during `string -> object` or `string -> list` conversions. + + + If this property is null, the default conversion is applied. enum: - none - quantity @@ -480,26 +547,29 @@ spec: - Input type: string fallbackValue: - description: The fallback value that should be returned - by the transform if now pattern matches. + description: |- + The fallback value that should be returned by the transform if now pattern + matches. x-kubernetes-preserve-unknown-fields: true patterns: - description: The patterns that should be tested - against the input string. Patterns are tested - in order. The value of the first match is used - as result of this transform. + description: |- + The patterns that should be tested against the input string. + Patterns are tested in order. The value of the first match is used as + result of this transform. items: - description: MatchTransformPattern is a transform - that returns the value that matches a pattern. + description: |- + MatchTransformPattern is a transform that returns the value that matches a + pattern. properties: literal: - description: Literal exactly matches the input - string (case sensitive). Is required if - `type` is `literal`. + description: |- + Literal exactly matches the input string (case sensitive). + Is required if `type` is `literal`. type: string regexp: - description: Regexp to match against the input - string. Is required if `type` is `regexp`. + description: |- + Regexp to match against the input string. + Is required if `type` is `regexp`. type: string result: description: The value that is used as result @@ -507,15 +577,17 @@ spec: x-kubernetes-preserve-unknown-fields: true type: default: literal - description: "Type specifies how the pattern - matches the input. \n * `literal` - the - pattern value has to exactly match (case - sensitive) the input string. This is the - default. \n * `regexp` - the pattern treated - as a regular expression against which the - input string is tested. Crossplane will - throw an error if the key is not a valid - regexp." + description: |- + Type specifies how the pattern matches the input. + + + * `literal` - the pattern value has to exactly match (case sensitive) the + input string. This is the default. + + + * `regexp` - the pattern treated as a regular expression against + which the input string is tested. Crossplane will throw an error if the + key is not a valid regexp. enum: - literal - regexp @@ -527,8 +599,9 @@ spec: type: array type: object math: - description: Math is used to transform the input via - mathematical operations such as multiplication. + description: |- + Math is used to transform the input via mathematical operations such as + multiplication. properties: clampMax: description: ClampMax makes sure that the value @@ -554,19 +627,18 @@ spec: type: string type: object string: - description: String is used to transform the input into - a string or a different kind of string. Note that - the input does not necessarily need to be a string. + description: |- + String is used to transform the input into a string or a different kind + of string. Note that the input does not necessarily need to be a string. properties: convert: - description: Optional conversion method to be specified. - `ToUpper` and `ToLower` change the letter case - of the input string. `ToBase64` and `FromBase64` - perform a base64 conversion based on the input - string. `ToJson` converts any input value into - its raw JSON representation. `ToSha1`, `ToSha256` - and `ToSha512` generate a hash value based on - the input converted to JSON. + description: |- + Optional conversion method to be specified. + `ToUpper` and `ToLower` change the letter case of the input string. + `ToBase64` and `FromBase64` perform a base64 conversion based on the input string. + `ToJson` converts any input value into its raw JSON representation. + `ToSha1`, `ToSha256` and `ToSha512` generate a hash value based on the input + converted to JSON. enum: - ToUpper - ToLower @@ -578,8 +650,9 @@ spec: - ToSha512 type: string fmt: - description: Format the input using a Go format - string. See https://golang.org/pkg/fmt/ for details. + description: |- + Format the input using a Go format string. See + https://golang.org/pkg/fmt/ for details. type: string regexp: description: Extract a match from the input using @@ -590,9 +663,9 @@ spec: matches the entire expression. type: integer match: - description: Match string. May optionally include - submatches, aka capture groups. See https://pkg.go.dev/regexp/ - for details. + description: |- + Match string. May optionally include submatches, aka capture groups. + See https://pkg.go.dev/regexp/ for details. type: string required: - match @@ -628,9 +701,9 @@ spec: type: array type: default: FromCompositeFieldPath - description: Type sets the patching behaviour to be used. - Each patch type may require its own fields to be set on - the ComposedPatch object. + description: |- + Type sets the patching behaviour to be used. Each patch type may require + its own fields to be set on the ComposedPatch object. enum: - FromCompositeFieldPath - ToCompositeFieldPath @@ -649,19 +722,21 @@ spec: type: object type: array resources: - description: Resources is a list of resource templates that will be used - when a composite resource is created. + description: |- + Resources is a list of resource templates that will be used when a + composite resource is created. items: - description: ComposedTemplate is used to provide information about how - the composed resource should be processed. + description: |- + ComposedTemplate is used to provide information about how the composed + resource should be processed. properties: base: - description: Base of the composed resource that patches will be - applied to and from. If base is omitted, a previous Function within - the pipeline must have produced the named composed resource. Patches - will be applied to and from that resource. If base is specified, - and a previous Function within the pipeline produced the name - composed resource, it will be overwritten. + description: |- + Base of the composed resource that patches will be applied to and from. + If base is omitted, a previous Function within the pipeline must have + produced the named composed resource. Patches will be applied to and from + that resource. If base is specified, and a previous Function within the + pipeline produced the name composed resource, it will be overwritten. type: object x-kubernetes-embedded-resource: true x-kubernetes-preserve-unknown-fields: true @@ -670,42 +745,45 @@ spec: resource will render type: string connectionDetails: - description: ConnectionDetails lists the propagation secret keys - from this composed resource to the composition instance connection - secret. + description: |- + ConnectionDetails lists the propagation secret keys from this composed + resource to the composition instance connection secret. items: - description: ConnectionDetail includes the information about the - propagation of the connection information from one secret to - another. + description: |- + ConnectionDetail includes the information about the propagation of the connection + information from one secret to another. properties: fromConnectionSecretKey: - description: FromConnectionSecretKey is the key that will - be used to fetch the value from the composed resource's - connection secret. + description: |- + FromConnectionSecretKey is the key that will be used to fetch the value + from the composed resource's connection secret. type: string fromFieldPath: - description: FromFieldPath is the path of the field on the - composed resource whose value to be used as input. Name - must be specified if the type is FromFieldPath. + description: |- + FromFieldPath is the path of the field on the composed resource whose + value to be used as input. Name must be specified if the type is + FromFieldPath. type: string name: - description: Name of the connection secret key that will be - propagated to the connection secret of the composed resource. + description: |- + Name of the connection secret key that will be propagated to the + connection secret of the composed resource. type: string type: - description: Type sets the connection detail fetching behavior - to be used. Each connection detail type may require its - own fields to be set on the ConnectionDetail object. + description: |- + Type sets the connection detail fetching behavior to be used. Each + connection detail type may require its own fields to be set on the + ConnectionDetail object. enum: - FromConnectionSecretKey - FromFieldPath - FromValue type: string value: - description: Value that will be propagated to the connection - secret of the composite resource. May be set to inject a - fixed, non-sensitive connection secret value, for example - a well-known port. + description: |- + Value that will be propagated to the connection secret of the composite + resource. May be set to inject a fixed, non-sensitive connection secret + value, for example a well-known port. type: string required: - name @@ -719,47 +797,51 @@ spec: patches: description: Patches to and from the composed resource. items: - description: ComposedPatch objects are applied between composite - and composed resources. Their behaviour depends on the Type - selected. The default Type, FromCompositeFieldPath, copies a - value from the composite resource to the composed resource, - applying any defined transformers. + description: |- + ComposedPatch objects are applied between composite and composed resources. + Their behaviour depends on the Type selected. The default Type, + FromCompositeFieldPath, copies a value from the composite resource to the + composed resource, applying any defined transformers. properties: combine: - description: Combine is the patch configuration for a CombineFromComposite, + description: |- + Combine is the patch configuration for a CombineFromComposite, CombineToComposite patch. properties: strategy: - description: Strategy defines the strategy to use to combine - the input variable values. Currently only string is - supported. + description: |- + Strategy defines the strategy to use to combine the input variable values. + Currently only string is supported. enum: - string type: string string: - description: String declares that input variables should - be combined into a single string, using the relevant - settings for formatting purposes. + description: |- + String declares that input variables should be combined into a single + string, using the relevant settings for formatting purposes. properties: fmt: - description: Format the input using a Go format string. - See https://golang.org/pkg/fmt/ for details. + description: |- + Format the input using a Go format string. See + https://golang.org/pkg/fmt/ for details. type: string required: - fmt type: object variables: - description: Variables are the list of variables whose - values will be retrieved and combined. + description: |- + Variables are the list of variables whose values will be retrieved and + combined. items: - description: A CombineVariable defines the source of - a value that is combined with others to form and patch - an output value. Currently, this only supports retrieving - values from a field path. + description: |- + A CombineVariable defines the source of a value that is combined with + others to form and patch an output value. Currently, this only supports + retrieving values from a field path. properties: fromFieldPath: - description: FromFieldPath is the path of the field - on the source whose value is to be used as input. + description: |- + FromFieldPath is the path of the field on the source whose value is + to be used as input. type: string required: - fromFieldPath @@ -771,9 +853,10 @@ spec: - variables type: object fromFieldPath: - description: FromFieldPath is the path of the field on the - resource whose value is to be used as input. Required when - type is FromCompositeFieldPath or ToCompositeFieldPath. + description: |- + FromFieldPath is the path of the field on the resource whose value is + to be used as input. Required when type is FromCompositeFieldPath or + ToCompositeFieldPath. type: string patchSetName: description: PatchSetName to include patches from. Required @@ -783,41 +866,59 @@ spec: description: Policy configures the specifics of patching behaviour. properties: fromFieldPath: - description: FromFieldPath specifies how to patch from - a field path. The default is 'Optional', which means - the patch will be a no-op if the specified fromFieldPath - does not exist. Use 'Required' if the patch should fail - if the specified path does not exist. + description: |- + FromFieldPath specifies how to patch from a field path. The default is + 'Optional', which means the patch will be a no-op if the specified + fromFieldPath does not exist. Use 'Required' to prevent the creation of a + new composed resource until the required path exists. enum: - Optional - Required type: string + toFieldPath: + description: |- + ToFieldPath specifies how to patch to a field path. The default is + 'Replace', which means the patch will completely replace the target field, + or create it if it does not exist. Use 'MergeObject' to merge the patch + object with the target object, or 'AppendArray' to append the patch array + to the target array. + enum: + - Replace + - MergeObject + - AppendArray + type: string type: object toFieldPath: - description: ToFieldPath is the path of the field on the resource - whose value will be changed with the result of transforms. - Leave empty if you'd like to propagate to the same path - as fromFieldPath. + description: |- + ToFieldPath is the path of the field on the resource whose value will + be changed with the result of transforms. Leave empty if you'd like to + propagate to the same path as fromFieldPath. type: string transforms: - description: Transforms are the list of functions that are - used as a FIFO pipe for the input to be transformed. + description: |- + Transforms are the list of functions that are used as a FIFO pipe for the + input to be transformed. items: - description: Transform is a unit of process whose input - is transformed into an output with the supplied configuration. + description: |- + Transform is a unit of process whose input is transformed into an output with + the supplied configuration. properties: convert: description: Convert is used to cast the input into the given output type. properties: format: - description: "The expected input format. \n * `quantity` - - parses the input as a K8s [`resource.Quantity`](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity). + description: |- + The expected input format. + + + * `quantity` - parses the input as a K8s [`resource.Quantity`](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity). Only used during `string -> float64` conversions. * `json` - parses the input as a JSON string. - Only used during `string -> object` or `string - -> list` conversions. \n If this property is null, - the default conversion is applied." + Only used during `string -> object` or `string -> list` conversions. + + + If this property is null, the default conversion is applied. enum: - none - quantity @@ -857,26 +958,29 @@ spec: - Input type: string fallbackValue: - description: The fallback value that should be returned - by the transform if now pattern matches. + description: |- + The fallback value that should be returned by the transform if now pattern + matches. x-kubernetes-preserve-unknown-fields: true patterns: - description: The patterns that should be tested - against the input string. Patterns are tested - in order. The value of the first match is used - as result of this transform. + description: |- + The patterns that should be tested against the input string. + Patterns are tested in order. The value of the first match is used as + result of this transform. items: - description: MatchTransformPattern is a transform - that returns the value that matches a pattern. + description: |- + MatchTransformPattern is a transform that returns the value that matches a + pattern. properties: literal: - description: Literal exactly matches the input - string (case sensitive). Is required if - `type` is `literal`. + description: |- + Literal exactly matches the input string (case sensitive). + Is required if `type` is `literal`. type: string regexp: - description: Regexp to match against the input - string. Is required if `type` is `regexp`. + description: |- + Regexp to match against the input string. + Is required if `type` is `regexp`. type: string result: description: The value that is used as result @@ -884,15 +988,17 @@ spec: x-kubernetes-preserve-unknown-fields: true type: default: literal - description: "Type specifies how the pattern - matches the input. \n * `literal` - the - pattern value has to exactly match (case - sensitive) the input string. This is the - default. \n * `regexp` - the pattern treated - as a regular expression against which the - input string is tested. Crossplane will - throw an error if the key is not a valid - regexp." + description: |- + Type specifies how the pattern matches the input. + + + * `literal` - the pattern value has to exactly match (case sensitive) the + input string. This is the default. + + + * `regexp` - the pattern treated as a regular expression against + which the input string is tested. Crossplane will throw an error if the + key is not a valid regexp. enum: - literal - regexp @@ -904,8 +1010,9 @@ spec: type: array type: object math: - description: Math is used to transform the input via - mathematical operations such as multiplication. + description: |- + Math is used to transform the input via mathematical operations such as + multiplication. properties: clampMax: description: ClampMax makes sure that the value @@ -931,19 +1038,18 @@ spec: type: string type: object string: - description: String is used to transform the input into - a string or a different kind of string. Note that - the input does not necessarily need to be a string. + description: |- + String is used to transform the input into a string or a different kind + of string. Note that the input does not necessarily need to be a string. properties: convert: - description: Optional conversion method to be specified. - `ToUpper` and `ToLower` change the letter case - of the input string. `ToBase64` and `FromBase64` - perform a base64 conversion based on the input - string. `ToJson` converts any input value into - its raw JSON representation. `ToSha1`, `ToSha256` - and `ToSha512` generate a hash value based on - the input converted to JSON. + description: |- + Optional conversion method to be specified. + `ToUpper` and `ToLower` change the letter case of the input string. + `ToBase64` and `FromBase64` perform a base64 conversion based on the input string. + `ToJson` converts any input value into its raw JSON representation. + `ToSha1`, `ToSha256` and `ToSha512` generate a hash value based on the input + converted to JSON. enum: - ToUpper - ToLower @@ -955,8 +1061,9 @@ spec: - ToSha512 type: string fmt: - description: Format the input using a Go format - string. See https://golang.org/pkg/fmt/ for details. + description: |- + Format the input using a Go format string. See + https://golang.org/pkg/fmt/ for details. type: string regexp: description: Extract a match from the input using @@ -967,9 +1074,9 @@ spec: matches the entire expression. type: integer match: - description: Match string. May optionally include - submatches, aka capture groups. See https://pkg.go.dev/regexp/ - for details. + description: |- + Match string. May optionally include submatches, aka capture groups. + See https://pkg.go.dev/regexp/ for details. type: string required: - match @@ -1005,9 +1112,9 @@ spec: type: array type: default: FromCompositeFieldPath - description: Type sets the patching behaviour to be used. - Each patch type may require its own fields to be set on - the ComposedPatch object. + description: |- + Type sets the patching behaviour to be used. Each patch type may require + its own fields to be set on the ComposedPatch object. enum: - FromCompositeFieldPath - PatchSet @@ -1027,13 +1134,15 @@ spec: status: "True" type: Ready type: MatchCondition - description: ReadinessChecks allows users to define custom readiness - checks. All checks have to return true in order for resource to - be considered ready. The default readiness check is to have the - "Ready" condition to be "True". + description: |- + ReadinessChecks allows users to define custom readiness checks. All + checks have to return true in order for resource to be considered ready. + The default readiness check is to have the "Ready" condition to be + "True". items: - description: ReadinessCheck is used to indicate how to tell whether - a resource is ready for consumption + description: |- + ReadinessCheck is used to indicate how to tell whether a resource is ready + for consumption properties: fieldPath: description: FieldPath shows the path of the field whose value diff --git a/patches.go b/patches.go index 57fecdf..a8458a3 100644 --- a/patches.go +++ b/patches.go @@ -5,24 +5,28 @@ import ( "strings" "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/crossplane/function-sdk-go/resource/composed" + "github.com/crossplane/function-sdk-go/resource/composite" + + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) const ( - errPatchSetType = "a patch in a PatchSet cannot be of type PatchSet" - errCombineRequiresVariables = "combine patch types require at least one variable" + errPatchSetType = "a patch in a PatchSet cannot be of type PatchSet" errFmtUndefinedPatchSet = "cannot find PatchSet by name %s" - errFmtInvalidPatchType = "patch type %s is unsupported" errFmtCombineStrategyNotSupported = "combine strategy %s is not supported" errFmtCombineConfigMissing = "given combine strategy %s requires configuration" errFmtCombineStrategyFailed = "%s strategy could not combine" errFmtExpandingArrayFieldPaths = "cannot expand ToFieldPath %s" + errFmtInvalidPatchPolicy = "invalid patch policy %s" ) // A PatchInterface is a patch that can be applied between resources. @@ -41,50 +45,6 @@ type PatchWithPatchSetName interface { GetPatchSetName() string } -// Apply executes a patching operation between the from and to resources. -// Applies all patch types unless an 'only' filter is supplied. -func Apply(p PatchInterface, xr resource.Composite, cd resource.Composed, only ...v1beta1.PatchType) error { - return ApplyToObjects(p, xr, cd, only...) -} - -// ApplyToObjects works like Apply but accepts any kind of runtime.Object. It -// might be vulnerable to conversion panics (see -// https://github.com/crossplane/crossplane/pull/3394 for details). -func ApplyToObjects(p PatchInterface, a, b runtime.Object, only ...v1beta1.PatchType) error { - if filterPatch(p, only...) { - return nil - } - - switch p.GetType() { - case v1beta1.PatchTypeFromCompositeFieldPath, v1beta1.PatchTypeFromEnvironmentFieldPath: - return ApplyFromFieldPathPatch(p, a, b) - case v1beta1.PatchTypeToCompositeFieldPath, v1beta1.PatchTypeToEnvironmentFieldPath: - return ApplyFromFieldPathPatch(p, b, a) - case v1beta1.PatchTypeCombineFromComposite, v1beta1.PatchTypeCombineFromEnvironment: - return ApplyCombineFromVariablesPatch(p, a, b) - case v1beta1.PatchTypeCombineToComposite, v1beta1.PatchTypeCombineToEnvironment: - return ApplyCombineFromVariablesPatch(p, b, a) - case v1beta1.PatchTypePatchSet: - // Already resolved - nothing to do. - } - return errors.Errorf(errFmtInvalidPatchType, p.GetType()) -} - -// filterPatch returns true if patch should be filtered (not applied) -func filterPatch(p PatchInterface, only ...v1beta1.PatchType) bool { - // filter does not apply if not set - if len(only) == 0 { - return false - } - - for _, patchType := range only { - if patchType == p.GetType() { - return false - } - } - return true -} - // ResolveTransforms applies a list of transforms to a patch value. func ResolveTransforms(ts []v1beta1.Transform, input any) (any, error) { var err error @@ -101,19 +61,12 @@ func ResolveTransforms(ts []v1beta1.Transform, input any) (any, error) { // on the "from" resource. Values may be transformed if any are defined on // the patch. func ApplyFromFieldPathPatch(p PatchInterface, from, to runtime.Object) error { - if p.GetFromFieldPath() == "" { - return errors.Errorf(errFmtRequiredField, "FromFieldPath", p.GetType()) - } - fromMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(from) if err != nil { return err } in, err := fieldpath.Pave(fromMap).GetValue(p.GetFromFieldPath()) - if IsOptionalFieldPathNotFound(err, p.GetPolicy()) { - return nil - } if err != nil { return err } @@ -129,43 +82,55 @@ func ApplyFromFieldPathPatch(p PatchInterface, from, to runtime.Object) error { return patchFieldValueToMultiple(p.GetToFieldPath(), out, to) } - return errors.Wrap(patchFieldValueToObject(p.GetToFieldPath(), out, to), "cannot patch to object") + mo, err := toMergeOption(p) + if err != nil { + return err + } + + return errors.Wrap(patchFieldValueToObject(p.GetToFieldPath(), out, to, mo), "cannot patch to object") } -// ApplyCombineFromVariablesPatch patches the "to" resource, taking a list of -// input variables and combining them into a single output value. -// The single output value may then be further transformed if they are defined -// on the patch. -func ApplyCombineFromVariablesPatch(p PatchInterface, from, to runtime.Object) error { - // Combine patch requires configuration - if p.GetCombine() == nil { - return errors.Errorf(errFmtRequiredField, "Combine", p.GetType()) +// toMergeOption returns the MergeOptions from the PatchPolicy's ToFieldPathPolicy, if defined. +func toMergeOption(p PatchInterface) (mo *xpv1.MergeOptions, err error) { + if p == nil { + return nil, nil } - // Destination field path is required since we can't default to multiple - // fields. - if p.GetToFieldPath() == "" { - return errors.Errorf(errFmtRequiredField, "ToFieldPath", p.GetType()) + pp := p.GetPolicy() + if pp == nil { + return nil, nil } - - combine := p.GetCombine() - vl := len(combine.Variables) - - if vl < 1 { - return errors.New(errCombineRequiresVariables) + switch pp.GetToFieldPathPolicy() { + case v1beta1.ToFieldPathPolicyReplace: + // nothing to do, this is the default + case v1beta1.ToFieldPathPolicyAppendArray: + mo = &xpv1.MergeOptions{AppendSlice: ptr.To(true)} + case v1beta1.ToFieldPathPolicyMergeObject: + mo = &xpv1.MergeOptions{KeepMapValues: ptr.To(true)} + default: + // should never happen + return nil, errors.Errorf(errFmtInvalidPatchPolicy, pp.GetToFieldPathPolicy()) } + return mo, nil +} +// ApplyCombineFromVariablesPatch patches the "to" resource, taking a list of +// input variables and combining them into a single output value. The single +// output value may then be further transformed if they are defined on the +// patch. +func ApplyCombineFromVariablesPatch(p PatchInterface, from, to runtime.Object) error { fromMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(from) if err != nil { return err } - in := make([]any, vl) + c := p.GetCombine() + in := make([]any, len(c.Variables)) // Get value of each variable // NOTE: This currently assumes all variables define a 'fromFieldPath' // value. If we add new variable types, this may not be the case and // this code may be better served split out into a dedicated function. - for i, sp := range combine.Variables { + for i, sp := range c.Variables { iv, err := fieldpath.Pave(fromMap).GetValue(sp.FromFieldPath) // If any source field is not found, we will not @@ -174,9 +139,6 @@ func ApplyCombineFromVariablesPatch(p PatchInterface, from, to runtime.Object) e // number of inputs (e.g. a string format // expecting 3 fields '%s-%s-%s' but only // receiving 2 values). - if IsOptionalFieldPathNotFound(err, p.GetPolicy()) { - return nil - } if err != nil { return err } @@ -184,7 +146,7 @@ func ApplyCombineFromVariablesPatch(p PatchInterface, from, to runtime.Object) e } // Combine input values - cb, err := Combine(*p.GetCombine(), in) + cb, err := Combine(*c, in) if err != nil { return err } @@ -195,23 +157,111 @@ func ApplyCombineFromVariablesPatch(p PatchInterface, from, to runtime.Object) e return err } - return errors.Wrap(patchFieldValueToObject(p.GetToFieldPath(), out, to), "cannot patch to object") + return errors.Wrap(patchFieldValueToObject(p.GetToFieldPath(), out, to, nil), "cannot patch to object") } -// IsOptionalFieldPathNotFound returns true if the supplied error indicates a -// field path was not found, and the supplied policy indicates a patch from that -// field path was optional. -func IsOptionalFieldPathNotFound(err error, p *v1beta1.PatchPolicy) bool { - switch { - case p == nil: - fallthrough - case p.FromFieldPath == nil: - fallthrough - case *p.FromFieldPath == v1beta1.FromFieldPathPolicyOptional: - return fieldpath.IsNotFound(err) - default: +// ApplyEnvironmentPatch applies a patch to or from the environment. Patches to +// the environment are always from the observed XR. Patches from the environment +// are always to the desired XR. +func ApplyEnvironmentPatch(p *v1beta1.EnvironmentPatch, env *unstructured.Unstructured, oxr, dxr *composite.Unstructured) error { + switch p.GetType() { + // From observed XR to environment. + case v1beta1.PatchTypeFromCompositeFieldPath: + return ApplyFromFieldPathPatch(p, oxr, env) + case v1beta1.PatchTypeCombineFromComposite: + return ApplyCombineFromVariablesPatch(p, oxr, env) + + // From environment to desired XR. + case v1beta1.PatchTypeToCompositeFieldPath: + return ApplyFromFieldPathPatch(p, env, dxr) + case v1beta1.PatchTypeCombineToComposite: + return ApplyCombineFromVariablesPatch(p, env, dxr) + + // Invalid patch types in this context. + case v1beta1.PatchTypeFromEnvironmentFieldPath, + v1beta1.PatchTypeCombineFromEnvironment, + v1beta1.PatchTypeToEnvironmentFieldPath, + v1beta1.PatchTypeCombineToEnvironment: + // Nothing to do. + + case v1beta1.PatchTypePatchSet: + // Already resolved - nothing to do. + } + return nil +} + +// ApplyComposedPatch applies a patch to or from a composed resource. Patches +// from an observed composed resource can be to the desired XR, or to the +// environment. Patches to a desired composed resource can be from the observed +// XR, or from the environment. +func ApplyComposedPatch(p *v1beta1.ComposedPatch, ocd, dcd *composed.Unstructured, oxr, dxr *composite.Unstructured, env *unstructured.Unstructured) error { //nolint:gocyclo // Just a long switch. + // Don't return an error if we're patching from a composed resource that + // doesn't exist yet. We'll try patch from it once it's been created. + if ocd == nil && !ToComposedResource(p) { + return nil + } + + // We always patch from observed state to desired state. This is because + // folks will often want to patch from status fields, which only appear in + // observed state. Observed state should also eventually be consistent with + // desired state. + switch t := p.GetType(); t { + + // From observed composed resource to desired XR. + case v1beta1.PatchTypeToCompositeFieldPath: + return ApplyFromFieldPathPatch(p, ocd, dxr) + case v1beta1.PatchTypeCombineToComposite: + return ApplyCombineFromVariablesPatch(p, ocd, dxr) + + // From observed composed resource to environment. + case v1beta1.PatchTypeToEnvironmentFieldPath: + return ApplyFromFieldPathPatch(p, ocd, env) + case v1beta1.PatchTypeCombineToEnvironment: + return ApplyCombineFromVariablesPatch(p, ocd, env) + + // From observed XR to desired composed resource. + case v1beta1.PatchTypeFromCompositeFieldPath: + return ApplyFromFieldPathPatch(p, oxr, dcd) + case v1beta1.PatchTypeCombineFromComposite: + return ApplyCombineFromVariablesPatch(p, oxr, dcd) + + // From environment to desired composed resource. + case v1beta1.PatchTypeFromEnvironmentFieldPath: + return ApplyFromFieldPathPatch(p, env, dcd) + case v1beta1.PatchTypeCombineFromEnvironment: + return ApplyCombineFromVariablesPatch(p, env, dcd) + + case v1beta1.PatchTypePatchSet: + // Already resolved - nothing to do. + } + + return nil +} + +// ToComposedResource returns true if the supplied patch is to a composed +// resource, not from it. +func ToComposedResource(p *v1beta1.ComposedPatch) bool { + switch p.GetType() { + + // From observed XR to desired composed resource. + case v1beta1.PatchTypeFromCompositeFieldPath, v1beta1.PatchTypeCombineFromComposite: + return true + // From environment to desired composed resource. + case v1beta1.PatchTypeFromEnvironmentFieldPath, v1beta1.PatchTypeCombineFromEnvironment: + return true + + // From composed resource to composite. + case v1beta1.PatchTypeToCompositeFieldPath, v1beta1.PatchTypeCombineToComposite: + return false + // From composed resource to environment. + case v1beta1.PatchTypeToEnvironmentFieldPath, v1beta1.PatchTypeCombineToEnvironment: + return false + // We can ignore patchsets; they're inlined. + case v1beta1.PatchTypePatchSet: return false } + + return false } // Combine calls the appropriate combiner. @@ -246,7 +296,7 @@ func ComposedTemplates(pss []v1beta1.PatchSet, cts []v1beta1.ComposedTemplate) ( pn := make(map[string][]v1beta1.ComposedPatch) for _, s := range pss { for _, p := range s.Patches { - if p.Type == v1beta1.PatchTypePatchSet { + if p.GetType() == v1beta1.PatchTypePatchSet { return nil, errors.New(errPatchSetType) } } @@ -257,12 +307,12 @@ func ComposedTemplates(pss []v1beta1.PatchSet, cts []v1beta1.ComposedTemplate) ( for i, r := range cts { var po []v1beta1.ComposedPatch for _, p := range r.Patches { - if p.Type != v1beta1.PatchTypePatchSet { + if p.GetType() != v1beta1.PatchTypePatchSet { po = append(po, p) continue } if p.PatchSetName == nil { - return nil, errors.Errorf(errFmtRequiredField, "PatchSetName", p.Type) + return nil, errors.Errorf(errFmtRequiredField, "PatchSetName", p.GetType()) } ps, ok := pn[*p.PatchSetName] if !ok { @@ -278,13 +328,15 @@ func ComposedTemplates(pss []v1beta1.PatchSet, cts []v1beta1.ComposedTemplate) ( // patchFieldValueToObject applies the value to the "to" object at the given // path, returning any errors as they occur. -func patchFieldValueToObject(fieldPath string, value any, to runtime.Object) error { +// If no merge options is supplied, then destination field is replaced +// with the given value. +func patchFieldValueToObject(fieldPath string, value any, to runtime.Object, mo *xpv1.MergeOptions) error { paved, err := fieldpath.PaveObject(to) if err != nil { return err } - if err := paved.SetValue(fieldPath, value); err != nil { + if err := paved.MergeValue(fieldPath, value, mo); err != nil { return err } diff --git a/patches_test.go b/patches_test.go index 335a19c..1385ee0 100644 --- a/patches_test.go +++ b/patches_test.go @@ -8,34 +8,27 @@ import ( "github.com/pkg/errors" extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/utils/ptr" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composed" "github.com/crossplane/crossplane-runtime/pkg/test" + "github.com/crossplane/function-sdk-go/resource/composed" "github.com/crossplane/function-sdk-go/resource/composite" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) -func TestPatchApply(t *testing.T) { - errNotFound := func(path string) error { - p := &fieldpath.Paved{} - _, err := p.GetValue(path) - return err - } - +func TestApplyFromFieldPathPatch(t *testing.T) { type args struct { - patch v1beta1.ComposedPatch - xr *composite.Unstructured - cd *composed.Unstructured - only []v1beta1.PatchType + p PatchInterface + from runtime.Object + to runtime.Object } + type want struct { - xr *composite.Unstructured - cd *composed.Unstructured + to runtime.Object err error } @@ -44,559 +37,249 @@ func TestPatchApply(t *testing.T) { args want }{ - "InvalidCompositeFieldPathPatch": { - reason: "Should return error when required fields not passed to applyFromFieldPathPatch", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeFromCompositeFieldPath, - // This is missing fields. - }, - xr: &composite.Unstructured{}, - cd: &composed.Unstructured{}, - }, - want: want{ - err: errors.Errorf(errFmtRequiredField, "FromFieldPath", v1beta1.PatchTypeFromCompositeFieldPath), - }, - }, - "Invalidv1.PatchType": { - reason: "Should return an error if an invalid patch type is specified", + "ValidFromCompositeFieldPath": { + reason: "Should correctly apply a valid FromCompositeFieldPath patch", args: args{ - patch: v1beta1.ComposedPatch{ - Type: "invalid-patchtype", - }, - xr: &composite.Unstructured{}, - cd: &composed.Unstructured{}, - }, - want: want{ - err: errors.Errorf(errFmtInvalidPatchType, "invalid-patchtype"), - }, - }, - "ValidCompositeFieldPathPatch": { - reason: "Should correctly apply a CompositeFieldPathPatch with valid settings", - args: args{ - patch: v1beta1.ComposedPatch{ + p: &v1beta1.ComposedPatch{ Type: v1beta1.PatchTypeFromCompositeFieldPath, Patch: v1beta1.Patch{ FromFieldPath: ptr.To[string]("metadata.labels"), ToFieldPath: ptr.To[string]("metadata.labels"), }, }, - xr: &composite.Unstructured{ + from: &composite.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "test": "blah" + "apiVersion": "test.crossplane.io/v1", + "kind": "XR", + "metadata": { + "labels": { + "test": "blah" + } } - } - }`)}, + }`)}, }, - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "cd" - } - }`)}, + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "name": "cd" + } + }`)}, }, }, want: want{ - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "cd", - "labels": { - "test": "blah" + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "name": "cd", + "labels": { + "test": "blah" + } } - } - }`)}, + }`)}, }, err: nil, }, }, - "ValidCompositeFieldPathPatchWithWildcards": { + "ValidFromFieldPathWithWildcards": { reason: "When passed a wildcarded path, adds a field to each element of an array", args: args{ - patch: v1beta1.ComposedPatch{ + p: &v1beta1.ComposedPatch{ Type: v1beta1.PatchTypeFromCompositeFieldPath, Patch: v1beta1.Patch{ FromFieldPath: ptr.To[string]("metadata.name"), ToFieldPath: ptr.To[string]("metadata.ownerReferences[*].name"), }, }, - xr: &composite.Unstructured{ + from: &composite.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "name": "test" - } - }`)}, + "apiVersion": "test.crossplane.io/v1", + "kind": "XR", + "metadata": { + "name": "test" + } + }`)}, }, - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "ownerReferences": [ - { - "name": "" - }, - { - "name": "" - } - ] - } - }`)}, + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "ownerReferences": [ + { + "name": "" + }, + { + "name": "" + } + ] + } + }`)}, }, }, want: want{ - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "ownerReferences": [ - { - "name": "test" - }, - { - "name": "test" - } - ] - } - }`)}, + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "ownerReferences": [ + { + "name": "test" + }, + { + "name": "test" + } + ] + } + }`)}, }, }, }, "InvalidCompositeFieldPathPatchWithWildcards": { reason: "When passed a wildcarded path, throws an error if ToFieldPath cannot be expanded", args: args{ - patch: v1beta1.ComposedPatch{ + p: &v1beta1.ComposedPatch{ Type: v1beta1.PatchTypeFromCompositeFieldPath, Patch: v1beta1.Patch{ FromFieldPath: ptr.To[string]("metadata.name"), ToFieldPath: ptr.To[string]("metadata.ownerReferences[*].badField"), }, }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "name": "test" - } - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "ownerReferences": [ - { - "name": "test" - }, - { - "name": "test" - } - ] - } - }`)}, - }, - }, - want: want{ - err: errors.Errorf(errFmtExpandingArrayFieldPaths, "metadata.ownerReferences[*].badField"), - }, - }, - "MissingOptionalFieldPath": { - reason: "A FromFieldPath patch should be a no-op when an optional fromFieldPath doesn't exist", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeFromCompositeFieldPath, - Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("metadata.labels"), - ToFieldPath: ptr.To[string]("metadata.labels"), - }, - }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "name": "test" - } - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "test" - } - }`)}, - }, - }, - want: want{ - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "test" - } - }`)}, - }, - err: nil, - }, - }, - "MissingRequiredFieldPath": { - reason: "A FromFieldPath patch should return an error when a required fromFieldPath doesn't exist", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeFromCompositeFieldPath, - Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("wat"), - Policy: &v1beta1.PatchPolicy{ - FromFieldPath: func() *v1beta1.FromFieldPathPolicy { - s := v1beta1.FromFieldPathPolicyRequired - return &s - }(), - }, - ToFieldPath: ptr.To[string]("wat"), - }, - }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "name": "test" - } - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "test" - } - }`)}, - }, - }, - want: want{ - cd: &composed.Unstructured{ + from: &composite.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "test" - } - }`)}, - }, - err: errNotFound("wat"), - }, - }, - "FilterExcludeCompositeFieldPathPatch": { - reason: "Should not apply the patch as the v1.PatchType is not present in filter.", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeFromCompositeFieldPath, - Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("metadata.labels"), - ToFieldPath: ptr.To[string]("metadata.labels"), - }, - }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "test": "blah" + "apiVersion": "test.crossplane.io/v1", + "kind": "XR", + "metadata": { + "name": "test" } - } - }`)}, - }, - cd: &composed.Unstructured{}, - only: []v1beta1.PatchType{v1beta1.PatchTypePatchSet}, - }, - want: want{ - cd: &composed.Unstructured{}, - err: nil, - }, - }, - "FilterIncludeCompositeFieldPathPatch": { - reason: "Should apply the patch as the v1.PatchType is present in filter.", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeFromCompositeFieldPath, - Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("metadata.labels"), - ToFieldPath: ptr.To[string]("metadata.labels"), - }, + }`)}, }, - xr: &composite.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "test": "blah" + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "ownerReferences": [ + { + "name": "test" + }, + { + "name": "test" + } + ] } - } - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed" - }`)}, + }`)}, }, - only: []v1beta1.PatchType{v1beta1.PatchTypeFromCompositeFieldPath}, }, want: want{ - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "labels": { - "test": "blah" + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "ownerReferences": [ + { + "name": "test" + }, + { + "name": "test" + } + ] } - } - }`)}, + }`)}, }, - err: nil, + err: errors.Errorf(errFmtExpandingArrayFieldPaths, "metadata.ownerReferences[*].badField"), }, }, "DefaultToFieldCompositeFieldPathPatch": { reason: "Should correctly default the ToFieldPath value if not specified.", args: args{ - patch: v1beta1.ComposedPatch{ + p: &v1beta1.ComposedPatch{ Type: v1beta1.PatchTypeFromCompositeFieldPath, Patch: v1beta1.Patch{ FromFieldPath: ptr.To[string]("metadata.labels"), }, }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "test": "blah" - } - } - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed" - }`)}, - }, - }, - want: want{ - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "labels": { - "test": "blah" - } - } - }`)}, - }, - err: nil, - }, - }, - "ValidToCompositeFieldPathPatch": { - reason: "Should correctly apply a ToCompositeFieldPath patch with valid settings", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeToCompositeFieldPath, - Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("metadata.labels"), - ToFieldPath: ptr.To[string]("metadata.labels"), - }, - }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR" - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "labels": { - "test": "blah" - } - } - }`)}, - }, - }, - want: want{ - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "test": "blah" - } - } - }`)}, - }, - err: nil, - }, - }, - "ValidToCompositeFieldPathPatchWithWildcards": { - reason: "When passed a wildcarded path, adds a field to each element of an array", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeToCompositeFieldPath, - Patch: v1beta1.Patch{ - FromFieldPath: ptr.To[string]("metadata.name"), - ToFieldPath: ptr.To[string]("metadata.ownerReferences[*].name"), - }, - }, - xr: &composite.Unstructured{ + from: &composite.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "ownerReferences": [ - { - "name": "" - }, - { - "name": "" + "apiVersion": "test.crossplane.io/v1", + "kind": "XR", + "metadata": { + "labels": { + "test": "blah" } - ] - } - }`)}, + } + }`)}, }, - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "name": "test" - } - }`)}, + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed" + }`)}, }, }, want: want{ - xr: &composite.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "ownerReferences": [ - { - "name": "test" - }, - { - "name": "test" + "apiVersion": "test.crossplane.io/v1", + "kind": "Composed", + "metadata": { + "labels": { + "test": "blah" } - ] - } - }`)}, - }, - }, - }, - "MissingCombineFromCompositeConfig": { - reason: "Should return an error if Combine config is not passed", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeCombineFromComposite, - Patch: v1beta1.Patch{ - ToFieldPath: ptr.To[string]("metadata.labels.destination"), - // Missing a Combine field - Combine: nil, - }, - }, - xr: &composite.Unstructured{}, - cd: &composed.Unstructured{}, - }, - want: want{ - xr: &composite.Unstructured{}, - cd: &composed.Unstructured{}, - err: errors.Errorf(errFmtRequiredField, "Combine", v1beta1.PatchTypeCombineFromComposite), - }, - }, - "MissingCombineStrategyFromCompositeConfig": { - reason: "Should return an error if Combine strategy config is not passed", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeCombineFromComposite, - Patch: v1beta1.Patch{ - Combine: &v1beta1.Combine{ - Variables: []v1beta1.CombineVariable{ - {FromFieldPath: "metadata.labels.source1"}, - {FromFieldPath: "metadata.labels.source2"}, - }, - Strategy: v1beta1.CombineStrategyString, - // Missing a String combine config. - }, - ToFieldPath: ptr.To[string]("metadata.labels.destination"), - }, - }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "source1": "a", - "source2": "b" } - } - }`)}, - }, - }, - want: want{ - err: errors.Errorf(errFmtCombineConfigMissing, v1beta1.CombineStrategyString), - }, - }, - "MissingCombineVariablesFromCompositeConfig": { - reason: "Should return an error if no variables have been passed", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeCombineFromComposite, - Patch: v1beta1.Patch{ - Combine: &v1beta1.Combine{ - // This is empty. - Variables: []v1beta1.CombineVariable{}, - Strategy: v1beta1.CombineStrategyString, - String: &v1beta1.StringCombine{Format: "%s-%s"}, - }, - ToFieldPath: ptr.To[string]("objectMeta.labels.destination"), - }, + }`)}, }, - }, - want: want{ - err: errors.New(errCombineRequiresVariables), + err: nil, }, }, - "NoOpOptionalInputFieldFromCompositeConfig": { - // Note: OptionalFieldPathNotFound is tested below, but we want to - // test that we abort the patch if _any_ of our source fields are - // not available. + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err := ApplyFromFieldPathPatch(tc.args.p, tc.args.from, tc.args.to) + + if diff := cmp.Diff(tc.want.to, tc.args.to); diff != "" { + t.Errorf("\n%s\nApplyFromFieldPathPatch(...): -want, +got:\n%s", tc.reason, diff) + } + + if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { + t.Errorf("\n%s\nApplyFromFieldPathPatch(): -want error, +got error:\n%s", tc.reason, diff) + } + }) + } +} + +func TestApplyCombineFromVariablesPatch(t *testing.T) { + errNotFound := func(path string) error { + p := &fieldpath.Paved{} + _, err := p.GetValue(path) + return err + } + + type args struct { + p PatchInterface + from runtime.Object + to runtime.Object + } + + type want struct { + to runtime.Object + err error + } + + cases := map[string]struct { + reason string + args + want + }{ + "VariableFromFieldPathNotFound": { reason: "Should return no error and not apply patch if an optional variable is missing", args: args{ - patch: v1beta1.ComposedPatch{ + p: &v1beta1.ComposedPatch{ Type: v1beta1.PatchTypeCombineFromComposite, Patch: v1beta1.Patch{ Combine: &v1beta1.Combine{ @@ -611,27 +294,21 @@ func TestPatchApply(t *testing.T) { ToFieldPath: ptr.To[string]("metadata.labels.destination"), }, }, - xr: &composite.Unstructured{ + from: &composite.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "source1": "foo", - "source3": "baz" - } - } - }`)}, + "apiVersion": "test.crossplane.io/v1", + "kind": "XR" + }`)}, }, }, want: want{ - err: nil, + err: errNotFound("metadata"), }, }, "ValidCombineFromComposite": { reason: "Should correctly apply a CombineFromComposite patch with valid settings", args: args{ - patch: v1beta1.ComposedPatch{ + p: &v1beta1.ComposedPatch{ Type: v1beta1.PatchTypeCombineFromComposite, Patch: v1beta1.Patch{ Combine: &v1beta1.Combine{ @@ -645,92 +322,35 @@ func TestPatchApply(t *testing.T) { ToFieldPath: ptr.To[string]("metadata.labels.destination"), }, }, - xr: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "XR", - "metadata": { - "labels": { - "source1": "foo", - "source2": "bar" - } - } - }`)}, - }, - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "labels": { - "test": "blah" - } - } - }`)}, - }, - }, - want: want{ - cd: &composed.Unstructured{ - Unstructured: unstructured.Unstructured{Object: MustObject(`{ - "apiVersion": "test.crossplane.io/v1", - "kind": "Composed", - "metadata": { - "labels": { - "destination": "foo-bar", - "test": "blah" - } - } - }`)}, - }, - err: nil, - }, - }, - "ValidCombineToComposite": { - reason: "Should correctly apply a CombineToComposite patch with valid settings", - args: args{ - patch: v1beta1.ComposedPatch{ - Type: v1beta1.PatchTypeCombineToComposite, - Patch: v1beta1.Patch{ - Combine: &v1beta1.Combine{ - Variables: []v1beta1.CombineVariable{ - {FromFieldPath: "metadata.labels.source1"}, - {FromFieldPath: "metadata.labels.source2"}, - }, - Strategy: v1beta1.CombineStrategyString, - String: &v1beta1.StringCombine{Format: "%s-%s"}, - }, - ToFieldPath: ptr.To[string]("metadata.labels.destination"), - }, - }, - xr: &composite.Unstructured{ + from: &composite.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ "apiVersion": "test.crossplane.io/v1", "kind": "XR", "metadata": { "labels": { - "test": "blah" + "source1": "foo", + "source2": "bar" } } }`)}, }, - cd: &composed.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ "apiVersion": "test.crossplane.io/v1", "kind": "Composed", "metadata": { "labels": { - "source1": "foo", - "source2": "bar" + "test": "blah" } } }`)}, }, }, want: want{ - xr: &composite.Unstructured{ + to: &composed.Unstructured{ Unstructured: unstructured.Unstructured{Object: MustObject(`{ "apiVersion": "test.crossplane.io/v1", - "kind": "XR", + "kind": "Composed", "metadata": { "labels": { "destination": "foo-bar", @@ -745,21 +365,14 @@ func TestPatchApply(t *testing.T) { } for name, tc := range cases { t.Run(name, func(t *testing.T) { - ncp := tc.args.xr.DeepCopyObject().(resource.Composite) - err := Apply(&tc.args.patch, ncp, tc.args.cd, tc.args.only...) + err := ApplyCombineFromVariablesPatch(tc.args.p, tc.args.from, tc.args.to) - if tc.want.xr != nil { - if diff := cmp.Diff(tc.want.xr, ncp); diff != "" { - t.Errorf("\n%s\nApply(cp): -want, +got:\n%s", tc.reason, diff) - } - } - if tc.want.cd != nil { - if diff := cmp.Diff(tc.want.cd, tc.args.cd); diff != "" { - t.Errorf("\n%s\nApply(cd): -want, +got:\n%s", tc.reason, diff) - } + if diff := cmp.Diff(tc.want.to, tc.args.to); diff != "" { + t.Errorf("\n%s\nApplyCombineFromVariablesPatch(...): -want, +got:\n%s", tc.reason, diff) } + if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { - t.Errorf("\n%s\nApply(err): -want, +got:\n%s", tc.reason, diff) + t.Errorf("\n%s\nApplyCombineFromVariablesPatch(): -want error, +got error:\n%s", tc.reason, diff) } }) } @@ -773,84 +386,6 @@ func MustObject(j string) map[string]any { return out } -func TestOptionalFieldPathNotFound(t *testing.T) { - errBoom := errors.New("boom") - errNotFound := func() error { - p := &fieldpath.Paved{} - _, err := p.GetValue("boom") - return err - } - required := v1beta1.FromFieldPathPolicyRequired - optional := v1beta1.FromFieldPathPolicyOptional - type args struct { - err error - p *v1beta1.PatchPolicy - } - - cases := map[string]struct { - reason string - args - want bool - }{ - "NotAnError": { - reason: "Should perform patch if no error finding field.", - args: args{}, - want: false, - }, - "NotFieldNotFoundError": { - reason: "Should return error if something other than field not found.", - args: args{ - err: errBoom, - }, - want: false, - }, - "DefaultOptionalNoPolicy": { - reason: "Should return no-op if field not found and no patch policy specified.", - args: args{ - err: errNotFound(), - }, - want: true, - }, - "DefaultOptionalNoPathPolicy": { - reason: "Should return no-op if field not found and empty patch policy specified.", - args: args{ - p: &v1beta1.PatchPolicy{}, - err: errNotFound(), - }, - want: true, - }, - "OptionalNotFound": { - reason: "Should return no-op if field not found and optional patch policy explicitly specified.", - args: args{ - p: &v1beta1.PatchPolicy{ - FromFieldPath: &optional, - }, - err: errNotFound(), - }, - want: true, - }, - "RequiredNotFound": { - reason: "Should return error if field not found and required patch policy explicitly specified.", - args: args{ - p: &v1beta1.PatchPolicy{ - FromFieldPath: &required, - }, - err: errNotFound(), - }, - want: false, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - got := IsOptionalFieldPathNotFound(tc.args.err, tc.args.p) - if diff := cmp.Diff(tc.want, got); diff != "" { - t.Errorf("IsOptionalFieldPathNotFound(...): -want, +got:\n%s", diff) - } - }) - } -} - func TestComposedTemplates(t *testing.T) { asJSON := func(val interface{}) extv1.JSON { raw, err := json.Marshal(val) diff --git a/ready.go b/ready.go index dd6ddd4..59de7ab 100644 --- a/ready.go +++ b/ready.go @@ -8,7 +8,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) // Error strings diff --git a/ready_test.go b/ready_test.go index bf0b8c9..a7e366a 100644 --- a/ready_test.go +++ b/ready_test.go @@ -14,7 +14,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composed" "github.com/crossplane/crossplane-runtime/pkg/test" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) var _ ReadinessChecker = ReadinessCheckerFn(IsReady) diff --git a/render.go b/render.go deleted file mode 100644 index 20398ea..0000000 --- a/render.go +++ /dev/null @@ -1,151 +0,0 @@ -package main - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/json" - - "github.com/crossplane/crossplane-runtime/pkg/errors" - "github.com/crossplane/crossplane-runtime/pkg/resource" - - "github.com/crossplane/function-sdk-go/resource/composed" - "github.com/crossplane/function-sdk-go/resource/composite" - - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" -) - -// Error strings -const ( - errUnmarshalJSON = "cannot unmarshal JSON data" - - errFmtKindChanged = "cannot change the kind of a composed resource from %s to %s (possible composed resource template mismatch)" - errFmtNamePrefixLabel = "cannot find top-level composite resource name label %q in composite resource metadata" - - // TODO(negz): Include more detail such as field paths if they exist. - // Perhaps require each patch type to have a String() method to help - // identify it. - errFmtPatch = "cannot apply the %q patch at index %d" -) - -// RenderFromJSON renders the supplied resource from JSON bytes. -func RenderFromJSON(o resource.Object, data []byte) error { - gvk := o.GetObjectKind().GroupVersionKind() - name := o.GetName() - namespace := o.GetNamespace() - - if err := json.Unmarshal(data, o); err != nil { - return errors.Wrap(err, errUnmarshalJSON) - } - - // TODO(negz): Should we return an error if the name or namespace change, - // rather than just silently re-setting it? Presumably these _changing_ is a - // sign that something has gone wrong, similar to the GVK changing. What - // about the UID changing? - - // Unmarshalling the template will overwrite any existing fields, so we must - // restore the existing name, if any. - o.SetName(name) - o.SetNamespace(namespace) - - // This resource already had a GVK (probably because it already exists), but - // when we rendered its template it changed. This shouldn't happen. Either - // someone changed the kind in the template or we're trying to use the wrong - // template (e.g. because the order of an array of anonymous templates - // changed). - empty := schema.GroupVersionKind{} - if gvk != empty && o.GetObjectKind().GroupVersionKind() != gvk { - return errors.Errorf(errFmtKindChanged, gvk, o.GetObjectKind().GroupVersionKind()) - } - - return nil -} - -// RenderEnvironmentPatches renders the supplied environment by applying all -// patches that are to the environment, from the supplied XR. -func RenderEnvironmentPatches(env *unstructured.Unstructured, oxr, dxr *composite.Unstructured, ps []v1beta1.EnvironmentPatch) error { - for i, p := range ps { - p := p - switch p.Type { - case v1beta1.PatchTypeToEnvironmentFieldPath, v1beta1.PatchTypeCombineToEnvironment: - if err := ApplyToObjects(&p, env, oxr); err != nil { - return errors.Wrapf(err, errFmtPatch, p.Type, i) - } - case v1beta1.PatchTypeFromEnvironmentFieldPath, v1beta1.PatchTypeCombineFromEnvironment: - if err := ApplyToObjects(&p, env, dxr); err != nil { - return errors.Wrapf(err, errFmtPatch, p.Type, i) - } - case v1beta1.PatchTypePatchSet, v1beta1.PatchTypeFromCompositeFieldPath, v1beta1.PatchTypeCombineFromComposite, v1beta1.PatchTypeToCompositeFieldPath, v1beta1.PatchTypeCombineToComposite: - // nothing to do - } - } - return nil -} - -// RenderComposedPatches renders the supplied composed resource by applying all -// patches that are to or from the supplied composite resource and environment -// in the order they were defined. Properly selecting the right source or -// destination between observed and desired resources. -func RenderComposedPatches( //nolint:gocyclo // just a switch - ocd *composed.Unstructured, - dcd *composed.Unstructured, - oxr *composite.Unstructured, - dxr *composite.Unstructured, - env *unstructured.Unstructured, - ps []v1beta1.ComposedPatch, -) (errs []error, store bool) { - for i, p := range ps { - p := p - switch t := p.Type; t { - case v1beta1.PatchTypeToCompositeFieldPath, v1beta1.PatchTypeCombineToComposite: - // TODO(negz): Should failures to patch the XR be terminal? It could - // indicate a required patch failed. A required patch means roughly - // "this patch has to succeed before you mutate the resource". This - // is useful to make sure we never create a composed resource in the - // wrong state. It's less clear how useful it is for the XR, given - // we'll only ever be updating it, not creating it. - - // We want to patch the XR from observed composed resources, not - // from desired state. This is because folks will typically be - // patching from a field that is set once the observed resource is - // applied such as its status. - if ocd == nil { - continue - } - if err := ApplyToObjects(&p, dxr, ocd); err != nil { - errs = append(errs, errors.Wrapf(err, errFmtPatch, t, i)) - } - case v1beta1.PatchTypeToEnvironmentFieldPath, v1beta1.PatchTypeCombineToEnvironment: - // TODO(negz): Same as above, but for the Environment. What does it - // mean for a required patch to the environment to fail? Should it - // be terminal? - - // Run all patches that are from the (observed) composed resource to - // the environment. - if ocd == nil { - continue - } - if err := ApplyToObjects(&p, env, ocd); err != nil { - errs = append(errs, errors.Wrapf(err, errFmtPatch, t, i)) - } - // If either of the below renderings return an error, most likely a - // required FromComposite or FromEnvironment patch failed. A required - // patch means roughly "this patch has to succeed before you mutate the - // resource." This is useful to make sure we never create a composed - // resource in the wrong state. To that end, we don't want to add this - // resource to our accumulated desired state. - case v1beta1.PatchTypeFromCompositeFieldPath, v1beta1.PatchTypeCombineFromComposite: - if err := ApplyToObjects(&p, oxr, dcd); err != nil { - errs = append(errs, errors.Wrapf(err, errFmtPatch, t, i)) - return errs, false - } - case v1beta1.PatchTypeFromEnvironmentFieldPath, v1beta1.PatchTypeCombineFromEnvironment: - if err := ApplyToObjects(&p, env, dcd); err != nil { - errs = append(errs, errors.Wrapf(err, errFmtPatch, t, i)) - return errs, false - } - case v1beta1.PatchTypePatchSet: - // Already resolved - nothing to do. - } - } - return errs, true -} diff --git a/render_test.go b/render_test.go deleted file mode 100644 index 8de503a..0000000 --- a/render_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package main - -import ( - "encoding/json" - "testing" - - "github.com/google/go-cmp/cmp" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - "github.com/crossplane/crossplane-runtime/pkg/errors" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/resource/fake" - "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composed" - "github.com/crossplane/crossplane-runtime/pkg/test" -) - -func TestRenderFromJSON(t *testing.T) { - errInvalidChar := json.Unmarshal([]byte("olala"), &fake.Composed{}) - - type args struct { - o resource.Object - data []byte - } - type want struct { - o resource.Object - err error - } - cases := map[string]struct { - reason string - args - want - }{ - "InvalidData": { - reason: "We should return an error if the data can't be unmarshalled", - args: args{ - o: &fake.Composed{}, - data: []byte("olala"), - }, - want: want{ - o: &fake.Composed{}, - err: errors.Wrap(errInvalidChar, errUnmarshalJSON), - }, - }, - "ExistingGVKChanged": { - reason: "We should return an error if unmarshalling the base template changed the composed resource's group, version, or kind", - args: args{ - o: composed.New(composed.FromReference(corev1.ObjectReference{ - APIVersion: "example.org/v1", - Kind: "Potato", - })), - data: []byte(`{"apiVersion": "example.org/v1", "kind": "Different"}`), - }, - want: want{ - o: composed.New(composed.FromReference(corev1.ObjectReference{ - APIVersion: "example.org/v1", - Kind: "Different", - })), - err: errors.Errorf(errFmtKindChanged, "example.org/v1, Kind=Potato", "example.org/v1, Kind=Different"), - }, - }, - "NewComposedResource": { - reason: "A valid base template should apply successfully to a new (empty) composed resource", - args: args{ - o: composed.New(), - data: []byte(`{"apiVersion": "example.org/v1", "kind": "Potato", "spec": {"cool": true}}`), - }, - want: want{ - o: &composed.Unstructured{Unstructured: unstructured.Unstructured{ - Object: map[string]any{ - "apiVersion": "example.org/v1", - "kind": "Potato", - "spec": map[string]any{ - "cool": true, - }, - }, - }}, - }, - }, - "ExistingComposedResource": { - reason: "A valid base template should apply successfully to a new (empty) composed resource", - args: args{ - o: composed.New(composed.FromReference(corev1.ObjectReference{ - APIVersion: "example.org/v1", - Kind: "Potato", - Name: "ola-superrandom", - })), - data: []byte(`{"apiVersion": "example.org/v1", "kind": "Potato", "spec": {"cool": true}}`), - }, - want: want{ - o: &composed.Unstructured{Unstructured: unstructured.Unstructured{ - Object: map[string]any{ - "apiVersion": "example.org/v1", - "kind": "Potato", - "metadata": map[string]any{ - "name": "ola-superrandom", - }, - "spec": map[string]any{ - "cool": true, - }, - }, - }}, - }, - }, - } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - err := RenderFromJSON(tc.args.o, tc.args.data) - if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { - t.Errorf("\n%s\nRenderFromJSON(...): -want error, +got error:\n%s", tc.reason, diff) - } - if diff := cmp.Diff(tc.want.o, tc.args.o); diff != "" { - t.Errorf("\n%s\nRenderFromJSON(...): -want, +got:\n%s", tc.reason, diff) - } - }) - } -} diff --git a/transforms.go b/transforms.go index 3d9d139..2a5ec4b 100644 --- a/transforms.go +++ b/transforms.go @@ -19,7 +19,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) const ( diff --git a/transforms_test.go b/transforms_test.go index bc42130..0ef111e 100644 --- a/transforms_test.go +++ b/transforms_test.go @@ -14,7 +14,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" "github.com/crossplane/crossplane-runtime/pkg/test" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) func TestMapResolve(t *testing.T) { diff --git a/validate.go b/validate.go index bcaf695..f0bbb77 100644 --- a/validate.go +++ b/validate.go @@ -6,7 +6,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) // WrapFieldError wraps the given field.Error adding the given field.Path as root of the Field. @@ -98,13 +98,14 @@ func ValidateEnvironment(e *v1beta1.Environment) *field.Error { } for i, p := range e.Patches { p := p - switch p.GetType() { //nolint:exhaustive // Intentionally targeting only environment patches. - case v1beta1.PatchTypeCombineToEnvironment, - v1beta1.PatchTypeCombineFromEnvironment, - v1beta1.PatchTypeFromEnvironmentFieldPath, - v1beta1.PatchTypeToEnvironmentFieldPath: + switch p.GetType() { //nolint:exhaustive // Only target valid patches according the API spec + case + v1beta1.PatchTypeFromCompositeFieldPath, + v1beta1.PatchTypeToCompositeFieldPath, + v1beta1.PatchTypeCombineFromComposite, + v1beta1.PatchTypeCombineToComposite: default: - return field.Invalid(field.NewPath("patches").Index(i).Key("type"), p.Type, "invalid environment patch type") + return field.Invalid(field.NewPath("patches").Index(i).Key("type"), p.GetType(), "invalid environment patch type") } if err := ValidatePatch(&p); err != nil { @@ -188,6 +189,7 @@ func ValidatePatch(p PatchInterface) *field.Error { //nolint: gocyclo // This is if p.GetToFieldPath() == "" { return field.Required(field.NewPath("toFieldPath"), fmt.Sprintf("toFieldPath must be set for patch type %s", p.GetType())) } + return WrapFieldError(ValidateCombine(p.GetCombine()), field.NewPath("combine")) default: // Should never happen return field.Invalid(field.NewPath("type"), p.GetType(), "unknown patch type") @@ -197,6 +199,48 @@ func ValidatePatch(p PatchInterface) *field.Error { //nolint: gocyclo // This is return WrapFieldError(err, field.NewPath("transforms").Index(i)) } } + if pp := p.GetPolicy(); pp != nil { + switch pp.GetToFieldPathPolicy() { + case v1beta1.ToFieldPathPolicyReplace, + v1beta1.ToFieldPathPolicyAppendArray, + v1beta1.ToFieldPathPolicyMergeObject: + // ok + default: + return field.Invalid(field.NewPath("policy", "toFieldPathPolicy"), pp.GetToFieldPathPolicy(), "unknown toFieldPathPolicy") + } + switch pp.GetFromFieldPathPolicy() { + case v1beta1.FromFieldPathPolicyRequired, + v1beta1.FromFieldPathPolicyOptional: + // ok + default: + return field.Invalid(field.NewPath("policy", "fromFieldPathPolicy"), pp.GetFromFieldPathPolicy(), "unknown fromFieldPathPolicy") + } + } + return nil +} + +// ValidateCombine validates a Combine. +func ValidateCombine(c *v1beta1.Combine) *field.Error { + switch c.Strategy { + case v1beta1.CombineStrategyString: + if c.String == nil { + return field.Required(field.NewPath("string"), fmt.Sprintf("string must be set for combine strategy %s", c.Strategy)) + } + case "": + return field.Required(field.NewPath("strategy"), "a combine strategy must be provided") + default: + return field.Invalid(field.NewPath("strategy"), c.Strategy, "unknown strategy type") + } + + if len(c.Variables) == 0 { + return field.Required(field.NewPath("variables"), "at least one variable must be provided") + } + + for i := range c.Variables { + if c.Variables[i].FromFieldPath == "" { + return field.Required(field.NewPath("variables").Index(i).Child("fromFieldPath"), "fromFieldPath must be set for each combine variable") + } + } return nil } diff --git a/validate_test.go b/validate_test.go index 479aefe..f5078bd 100644 --- a/validate_test.go +++ b/validate_test.go @@ -9,7 +9,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/utils/ptr" - "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" + "github.com/upboundcare/function-conditional-patch-and-transform/input/v1beta1" ) func TestValidateReadinessCheck(t *testing.T) { @@ -380,6 +380,131 @@ func TestValidatePatch(t *testing.T) { } } +func TestValidateCombine(t *testing.T) { + type args struct { + combine v1beta1.Combine + } + type want struct { + err *field.Error + } + + cases := map[string]struct { + reason string + args args + want want + }{ + "MissingStrategy": { + reason: "A combine with no strategy is invalid", + args: args{ + combine: v1beta1.Combine{}, + }, + want: want{ + err: &field.Error{ + Type: field.ErrorTypeRequired, + Field: "strategy", + }, + }, + }, + "InvalidStrategy": { + reason: "A combine with an unknown strategy is invalid", + args: args{ + combine: v1beta1.Combine{ + Strategy: "Smoosh", + }, + }, + want: want{ + err: &field.Error{ + Type: field.ErrorTypeInvalid, + Field: "strategy", + }, + }, + }, + "ValidStringCombine": { + reason: "A string combine with variables and a format string should be valid", + args: args{ + combine: v1beta1.Combine{ + Strategy: v1beta1.CombineStrategyString, + Variables: []v1beta1.CombineVariable{ + {FromFieldPath: "a"}, + {FromFieldPath: "b"}, + }, + String: &v1beta1.StringCombine{ + Format: "%s-%s", + }, + }, + }, + want: want{ + err: nil, + }, + }, + "MissingVariables": { + reason: "A combine with no variables is invalid", + args: args{ + combine: v1beta1.Combine{ + Strategy: v1beta1.CombineStrategyString, + String: &v1beta1.StringCombine{ + Format: "%s-%s", + }, + }, + }, + want: want{ + err: &field.Error{ + Type: field.ErrorTypeRequired, + Field: "variables", + }, + }, + }, + "VariableMissingFromFieldPath": { + reason: "A variable with no fromFieldPath is invalid", + args: args{ + combine: v1beta1.Combine{ + Strategy: v1beta1.CombineStrategyString, + Variables: []v1beta1.CombineVariable{ + {FromFieldPath: "a"}, + {FromFieldPath: ""}, // Missing. + }, + String: &v1beta1.StringCombine{ + Format: "%s-%s", + }, + }, + }, + want: want{ + err: &field.Error{ + Type: field.ErrorTypeRequired, + Field: "variables[1].fromFieldPath", + }, + }, + }, + "MissingStringConfig": { + reason: "A string combine with no string config is invalid", + args: args{ + combine: v1beta1.Combine{ + Strategy: v1beta1.CombineStrategyString, + Variables: []v1beta1.CombineVariable{ + {FromFieldPath: "a"}, + {FromFieldPath: "b"}, + }, + }, + }, + want: want{ + err: &field.Error{ + Type: field.ErrorTypeRequired, + Field: "string", + }, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err := ValidateCombine(&tc.args.combine) + if diff := cmp.Diff(tc.want.err, err, cmpopts.IgnoreFields(field.Error{}, "Detail", "BadValue")); diff != "" { + t.Errorf("%s\nValidateCombine(...): -want, +got:\n%s", tc.reason, diff) + } + }) + } +} + func TestValidateTransform(t *testing.T) { type args struct { transform v1beta1.Transform