diff --git a/.golangci.yml b/.golangci.yml index 1fd5806..5421bc0 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/crossplane-contrib/function-patch-and-transform) + - prefix(github.com/stevendborrelli/function-conditional-patch-and-transform) - blank - dot diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3ffd048 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ + +DOCKER := docker +GO := go + +GOLANGCI_VERSION := 1.55.2 + +test: + $(GO) test ./... + +lint: + $(DOCKER) run --rm -v $(CURDIR):/app -v ~/.cache/golangci-lint/v$(GOLANGCI_VERSION):/root/.cache -w /app golangci/golangci-lint:v$(GOLANGCI_VERSION) golangci-lint run --fix + +reviewable: test lint \ No newline at end of file diff --git a/README.md b/README.md index 73d1bcf..23b0aeb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ -# function-patch-and-transform -[![CI](https://github.com/crossplane-contrib/function-patch-and-transform/actions/workflows/ci.yml/badge.svg)](https://github.com/crossplane-contrib/function-patch-and-transform/actions/workflows/ci.yml) ![GitHub release (latest SemVer)](https://img.shields.io/github/release/crossplane-contrib/function-patch-and-transform) +# 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) + +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 +of individual resources. This [composition function][docs-functions] does everything Crossplane's built-in [patch & transform][docs-pandt] (P&T) composition does. Instead of @@ -18,7 +22,7 @@ spec: pipeline: - step: patch-and-transform functionRef: - name: function-patch-and-transform + name: function-conditional-patch-and-transform input: apiVersion: pt.fn.crossplane.io/v1beta1 kind: Resources @@ -152,7 +156,7 @@ $ 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/crossplane-contrib/function-go-templating +[fn-go-templating]: https://github.com/stevendborrelli/function-go-templating [#4617]: https://github.com/crossplane/crossplane/issues/4617 [#4746]: https://github.com/crossplane/crossplane/issues/4746 [go]: https://go.dev diff --git a/condition.go b/condition.go new file mode 100644 index 0000000..1b8cbab --- /dev/null +++ b/condition.go @@ -0,0 +1,84 @@ +package main + +import ( + "reflect" + + "github.com/google/cel-go/cel" + + "github.com/crossplane/crossplane-runtime/pkg/errors" + + fnv1beta1 "github.com/crossplane/function-sdk-go/proto/v1beta1" + + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" +) + +// NewCELEnvironment sets up the CEL Environment +func NewCELEnvironment() (*cel.Env, error) { + return cel.NewEnv( + cel.Types(&fnv1beta1.State{}), + cel.Variable("observed", cel.ObjectType("apiextensions.fn.proto.v1beta1.State")), + cel.Variable("desired", cel.ObjectType("apiextensions.fn.proto.v1beta1.State")), + ) +} + +// ToCELVars formats a RunFunctionRequest for CEL evaluation +func ToCELVars(req *fnv1beta1.RunFunctionRequest) map[string]any { + vars := make(map[string]any) + vars["desired"] = req.GetDesired() + vars["observed"] = req.GetObserved() + return vars +} + +// EvaluateCondition will evaluate a CEL expression +func EvaluateCondition(cs v1beta1.ConditionSpec, req *fnv1beta1.RunFunctionRequest) (bool, error) { + if cs.Expression == "" { + return false, nil + } + + env, err := NewCELEnvironment() + if err != nil { + return false, errors.Wrap(err, "CEL Env error") + } + + ast, iss := env.Parse(cs.Expression) + if iss.Err() != nil { + return false, errors.Wrap(iss.Err(), "CEL Parse error") + } + + // Type-check the expression for correctness. + checked, iss := env.Check(ast) + // Report semantic errors, if present. + if iss.Err() != nil { + return false, errors.Wrap(iss.Err(), "CEL TypeCheck error") + } + + // Ensure the output type is a bool. + if !reflect.DeepEqual(checked.OutputType(), cel.BoolType) { + return false, errors.Errorf( + "CEL Type error: expression '%s' must return a boolean, got %v instead", + cs.Expression, + checked.OutputType()) + } + + // Plan the program. + program, err := env.Program(checked) + if err != nil { + return false, errors.Wrap(err, "CEL program plan") + } + + // Convert our Function Request into map[string]any for CEL evaluation + vars := ToCELVars(req) + + // Evaluate the program without any additional arguments. + result, _, err := program.Eval(vars) + if err != nil { + return false, errors.Wrap(err, "CEL program Evaluation") + } + + ret, ok := result.Value().(bool) + if !ok { + return false, errors.Wrap(err, "CEL program did not return a bool") + } + + return ret, nil +} diff --git a/condition_test.go b/condition_test.go new file mode 100644 index 0000000..18a7bef --- /dev/null +++ b/condition_test.go @@ -0,0 +1,359 @@ +package main + +import ( + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/crossplane/crossplane-runtime/pkg/errors" + + 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" +) + +func TestEvaluateCondition(t *testing.T) { + dxr := `{"apiVersion":"nopexample.org/v1alpha1","kind":"XNopResource","metadata":{"name":"test-resource"},"spec":{"env":"dev","render":true}}` + oxr := `{"apiVersion":"nopexample.org/v1alpha1","kind":"XNopResource","metadata":{"name":"test-resource"},"spec":{"env":"dev","render":true},"status":{"id":"123","ready":false} }` + + type args struct { + cs v1beta1.ConditionSpec + req *fnv1beta1.RunFunctionRequest + } + type want struct { + ret bool + err error + } + + cases := map[string]struct { + reason string + args args + want want + }{ + "CELParseError": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "field = value"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: errors.New("CEL Parse error"), + }, + }, + "CELTypeError": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "size(desired.resources)"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: errors.New("CEL Type error: expression 'size(desired.resources)' must return a boolean, got int instead"), + }, + }, + "KeyError": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "badkey"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: errors.New("CEL TypeCheck error: ERROR: :1:1: undeclared reference to 'badkey' (in container '')\n | badkey\n | ^"), + }, + }, + "TrueDesired": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "desired.composite.resource.spec.env == \"dev\" "}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: true, + err: nil, + }, + }, + "TrueDesiredBool": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "desired.composite.resource.spec.render == true"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: true, + err: nil, + }, + }, + "FalseDesiredBool": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "desired.composite.resource.spec.render == false"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: nil, + }, + }, + "FalseObservedBool": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "observed.composite.resource.status.ready == true"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: nil, + }, + }, + "FalseLengthResources": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "size(desired.resources) == 0"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Resources: map[string]*fnv1beta1.Resource{ + "test": { + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","metadata":{"namespace":"default","name":"cool-42"}}`), + }, + }, + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: nil, + }, + }, + "TrueResourceMapKeyExists": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "\"test-resource\" in desired.resources"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Resources: map[string]*fnv1beta1.Resource{ + "test-resource": { + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","metadata":{"namespace":"default","name":"cool-42"}}`), + }, + }, + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: true, + err: nil, + }, + }, + "FalseResourceMapKeyExists": { + args: args{ + cs: v1beta1.ConditionSpec{Expression: "\"bad-resource\" in desired.resources"}, + 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"}`)}, + }, + }, + }), + Observed: &fnv1beta1.State{ + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(oxr), + }, + }, + Desired: &fnv1beta1.State{ + Resources: map[string]*fnv1beta1.Resource{ + "test-resource": { + Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","metadata":{"namespace":"default","name":"cool-42"}}`), + }, + }, + Composite: &fnv1beta1.Resource{ + Resource: resource.MustStructJSON(dxr), + }, + }, + }, + }, + want: want{ + ret: false, + err: nil, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + ret, err := EvaluateCondition(tc.args.cs, tc.args.req) + + if diff := cmp.Diff(tc.want.ret, ret); diff != "" { + t.Errorf("%s\nEvaluateCondition(...): -want ret, +got ret:\n%s", tc.reason, diff) + } + + if tc.want.err != nil || err != nil { + if !strings.HasPrefix(err.Error(), tc.want.err.Error()) { + t.Errorf("\nEvaluateCondition(...): -want err, +got err:\n-want (error starts with): %s\n-got: %s", tc.want.err.Error(), err) + } + } + + }) + } +} diff --git a/connection.go b/connection.go index abe77bc..2a248b6 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/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/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 4ae6f63..eafa683 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/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) func TestExtractConnectionDetails(t *testing.T) { diff --git a/example/composition.yaml b/example/composition.yaml index 2c73250..3bd9d2e 100644 --- a/example/composition.yaml +++ b/example/composition.yaml @@ -1,7 +1,7 @@ apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: - name: function-patch-and-transform + name: function-conditional-patch-and-transform spec: compositeTypeRef: apiVersion: example.crossplane.io/v1 @@ -10,7 +10,7 @@ spec: pipeline: - step: patch-and-transform functionRef: - name: function-patch-and-transform + name: function-conditional-patch-and-transform input: apiVersion: pt.fn.crossplane.io/v1beta1 kind: Resources diff --git a/examples/conditional-rendering/README.md b/examples/conditional-rendering/README.md new file mode 100644 index 0000000..f540c1a --- /dev/null +++ b/examples/conditional-rendering/README.md @@ -0,0 +1,99 @@ +# Conditional Execution of Patch-and-Transform + +This is an experimental fork using [The Common Expression Language (CEL)](https://github.com/google/cel-spec) to conditionally running the patch and transform function. + +For example,if you have an XR with the following manifest: + +```yaml +apiVersion: nop.example.org/v1alpha1 +kind: XNopResource +metadata: + name: test-resource +spec: + env: dev + render: false +``` + +and set a Condition of `observed.composite.resource.spec.render == true`, the function +will not run. + +## Running this example + +- Until 1.14 is released, install a development version of Crossplane. See [install Crossplane master](https://docs.crossplane.io/latest/software/install/#install-the-crossplane-master-helm-chart) +- Install the nop provider in `kubectl apply -f provider.yaml` +- Install the XRD & Composition in `kubectl apply -f definition.yaml -f composition.yaml` +- Install the Function `kubectl apply -f function.yaml` + +Finally install the xr: `kubectl apply -f xr` + +## Validate the Install + +Validate the Composite is ready: + +```shell +$ kubectl get composite +NAME SYNCED READY COMPOSITION AGE +test-resource True True xnopresources.nop.example.org 2m9s +``` + +Validate the resource has been generated. + +```shell +$ kubectl get nopresource +NAME READY SYNCED AGE +test-resource-mpw5s True True 27m +``` + +## Testing Conditions + +The `RunFunctionRequest` passed to the function looks similar to the following manifest. +This can be used in the [CEL Playground](https://playcel.undistro.io) to test +various conditions. + +Note that the function is passed an empty `desired{}` state as per design. + +```yaml +--- +observed: + composite: + resource: + apiVersion: nop.example.org/v1alpha1 + kind: XNopResource + metadata: + name: test-resource + spec: + env: dev + render: true +desired: {} +input: + apiVersion: pt.fn.crossplane.io/v1beta1 + condition: + expression: observed.composite.resource.spec.env == "dev" && observed.composite.resource.spec.render + == true + kind: Resources + resources: + - base: + apiVersion: nop.crossplane.io/v1alpha1 + kind: NopResource + spec: + forProvider: + conditionAfter: + - conditionStatus: 'True' + conditionType: Ready + time: 5s + connectionDetails: + - name: username + value: fakeuser + - name: password + value: verysecurepassword + - name: endpoint + value: 127.0.0.1 + fields: + arrayField: + - stringField: array + integerField: 42 + objectField: + stringField: object + stringField: string + name: test-resource +``` diff --git a/examples/conditional-rendering/composition.yaml b/examples/conditional-rendering/composition.yaml new file mode 100644 index 0000000..103ff0a --- /dev/null +++ b/examples/conditional-rendering/composition.yaml @@ -0,0 +1,44 @@ +--- +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: xnopresources.nop.example.org +spec: + compositeTypeRef: + apiVersion: nop.example.org/v1alpha1 + kind: XNopResource + mode: Pipeline + pipeline: + - step: conditional-patch-and-transform + functionRef: + name: function-patch-and-transform + input: + apiVersion: pt.fn.crossplane.io/v1beta1 + kind: Resources + condition: + expression: observed.composite.resource.spec.env == "dev" && observed.composite.resource.spec.render == true + resources: + - name: test-resource + base: + apiVersion: nop.crossplane.io/v1alpha1 + kind: NopResource + spec: + forProvider: + fields: + integerField: 42 + stringField: "string" + objectField: + stringField: "object" + arrayField: + - stringField: "array" + conditionAfter: + - time: 5s + conditionType: Ready + conditionStatus: "True" + connectionDetails: + - name: username + value: fakeuser + - name: password + value: verysecurepassword + - name: endpoint + value: 127.0.0.1 diff --git a/examples/conditional-rendering/definition.yaml b/examples/conditional-rendering/definition.yaml new file mode 100644 index 0000000..6eb29c4 --- /dev/null +++ b/examples/conditional-rendering/definition.yaml @@ -0,0 +1,24 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: CompositeResourceDefinition +metadata: + name: xnopresources.nop.example.org +spec: + group: nop.example.org + names: + kind: XNopResource + plural: xnopresources + versions: + - name: v1alpha1 + referenceable: true + served: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + env: + type: string + render: + type: boolean \ No newline at end of file diff --git a/examples/conditional-rendering/function.yaml b/examples/conditional-rendering/function.yaml new file mode 100644 index 0000000..7803bf9 --- /dev/null +++ b/examples/conditional-rendering/function.yaml @@ -0,0 +1,9 @@ +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: function-patch-and-transform + annotations: + xrender.crossplane.io/runtime: Development +spec: + package: index.docker.io/steve/function-patch-and-transform:v0.2.0 + packagePullPolicy: Always diff --git a/examples/conditional-rendering/provider.yaml b/examples/conditional-rendering/provider.yaml new file mode 100644 index 0000000..1e28f83 --- /dev/null +++ b/examples/conditional-rendering/provider.yaml @@ -0,0 +1,6 @@ +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-nop +spec: + package: xpkg.upbound.io/crossplane-contrib/provider-nop:v0.2.0 \ No newline at end of file diff --git a/examples/conditional-rendering/xr.yaml b/examples/conditional-rendering/xr.yaml new file mode 100644 index 0000000..a830c36 --- /dev/null +++ b/examples/conditional-rendering/xr.yaml @@ -0,0 +1,7 @@ +apiVersion: nop.example.org/v1alpha1 +kind: XNopResource +metadata: + name: test-resource +spec: + env: dev + render: true \ No newline at end of file diff --git a/fn.go b/fn.go index 7161787..ee5533e 100644 --- a/fn.go +++ b/fn.go @@ -17,9 +17,11 @@ import ( "github.com/crossplane/function-sdk-go/resource/composed" "github.com/crossplane/function-sdk-go/response" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) +const conditionError = "Condition error" + // Function performs patch-and-transform style Composition. type Function struct { fnv1beta1.UnimplementedFunctionRunnerServiceServer @@ -43,6 +45,21 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1beta1.RunFunctionRe return rsp, nil } + // Evaluate any Conditions using the values from the Observed XR + if input.Condition != nil { + // Evaluate the condition to see if we should run + run, err := EvaluateCondition(*input.Condition, req) + if err != nil { + response.Fatal(rsp, errors.Wrap(err, conditionError)) + return rsp, nil + } + if !run { + log.Debug("Condition evaluated to false. Skipping run.") + return rsp, nil + } + log.Debug("Condition evaluated to true.") + } + // Our input is an opaque object nested in a Composition, so unfortunately // it won't handle validation for us. if err := ValidateResources(input); err != nil { @@ -140,6 +157,21 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1beta1.RunFunctionRe dcd := &resource.DesiredComposed{Resource: composed.New()} + if t.Condition != nil { + // Evaluate the condition to see if we should skip this template. + run, err := EvaluateCondition(*t.Condition, req) + if err != nil { + log.Info(err.Error()) + response.Fatal(rsp, errors.Wrap(err, conditionError)) + return rsp, nil + } + if !run { + log.Debug("Condition evaluated to false. Skipping template.") + continue + } + log.Debug("Condition evaluated to true.") + } + // If we have a base template, render it into our desired resource. If a // previous Function produced a desired resource with this name we'll // overwrite it. If we don't have a base template we'll try to patch to diff --git a/fn_test.go b/fn_test.go index ea1fa3e..112229a 100644 --- a/fn_test.go +++ b/fn_test.go @@ -20,7 +20,7 @@ import ( "github.com/crossplane/function-sdk-go/resource" "github.com/crossplane/function-sdk-go/response" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) func TestRunFunction(t *testing.T) { diff --git a/go.mod b/go.mod index 4b2ffac..b172f45 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/crossplane-contrib/function-patch-and-transform +module github.com/stevendborrelli/function-conditional-patch-and-transform go 1.21 @@ -8,6 +8,7 @@ require ( github.com/alecthomas/kong v0.8.1 github.com/crossplane/crossplane-runtime v1.14.1 github.com/crossplane/function-sdk-go v0.1.0 + github.com/google/cel-go v0.16.1 github.com/google/go-cmp v0.6.0 github.com/pkg/errors v0.9.1 google.golang.org/protobuf v1.31.0 @@ -20,6 +21,7 @@ require ( require ( dario.cat/mergo v1.0.0 // indirect + github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // 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 @@ -57,7 +59,7 @@ require ( github.com/spf13/afero v1.10.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.8.4 // indirect + github.com/stoewer/go-strcase v1.2.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 @@ -71,6 +73,7 @@ require ( golang.org/x/tools v0.14.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 gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 154f53e..00ef314 100644 --- a/go.sum +++ b/go.sum @@ -40,10 +40,22 @@ 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= +github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ494= +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/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= @@ -59,21 +71,17 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/crossplane/crossplane-runtime v1.13.0 h1:EumInUbS8mXV7otwoI3xa0rPczexJOky4XLVlHxxjO0= -github.com/crossplane/crossplane-runtime v1.13.0/go.mod h1:FuKIC8Mg8hE2gIAMyf2wCPkxkFPz+VnMQiYWBq1/p5A= -github.com/crossplane/crossplane-runtime v1.14.0 h1:MFo93iOJLvYaMCaCoyH2vFWsHebdA1kv3QdOm7hcm5k= -github.com/crossplane/crossplane-runtime v1.14.0/go.mod h1:aOP+5W2wKpvthVs3pFNbVOe1jwrKYbJho0ThGNCVz9o= +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/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/function-sdk-go v0.0.0-20231016233407-0a4b30c5dacc h1:hhupaJGj8I4LXhWr9lCm5MZLeeTAiuFF+/mesGi1y/8= -github.com/crossplane/function-sdk-go v0.0.0-20231016233407-0a4b30c5dacc/go.mod h1:U3UsQAVOCrsUUQAYAyF25PlbSFR2WaLl89dLq58/b2s= 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/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.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 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= @@ -82,9 +90,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m 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 v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +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/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= @@ -95,7 +106,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 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 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 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= @@ -108,6 +118,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 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= @@ -144,6 +155,8 @@ 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/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= @@ -176,21 +189,48 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe 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.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/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/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-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/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/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= @@ -206,6 +246,7 @@ 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= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -219,6 +260,16 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn 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/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= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -227,9 +278,13 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/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/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -247,15 +302,16 @@ github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+Pymzi 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/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.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= 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/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +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/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= @@ -268,11 +324,25 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 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/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/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= @@ -282,6 +352,7 @@ 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= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -331,8 +402,7 @@ 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +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= @@ -378,8 +448,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ 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.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= 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= @@ -393,7 +461,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +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/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= @@ -503,15 +572,12 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f 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.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +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/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.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= -gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= 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= @@ -577,8 +643,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D 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/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +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= @@ -597,8 +663,6 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM 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.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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= @@ -623,6 +687,7 @@ 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= @@ -656,8 +721,6 @@ k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt 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.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= -sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= 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= @@ -666,7 +729,5 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm 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/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= 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/generate.go b/input/generate.go index 551cc2a..187e557 100644 --- a/input/generate.go +++ b/input/generate.go @@ -4,6 +4,7 @@ // NOTE(negz): See the below link for details on what is happening here. // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module +//go:generate rm -rf package/input //go:generate go run -tags generate sigs.k8s.io/controller-tools/cmd/controller-gen paths=./v1beta1 object crd:crdVersions=v1 output:artifacts:config=../package/input package input diff --git a/input/v1beta1/conditions.go b/input/v1beta1/conditions.go new file mode 100644 index 0000000..20736c3 --- /dev/null +++ b/input/v1beta1/conditions.go @@ -0,0 +1,10 @@ +package v1beta1 + +// ConditionSpec defines the condition for rendering. +// Conditions are defined using the Common Expression Language +// For more information refer to https://github.com/google/cel-spec +type ConditionSpec struct { + // Expression is the CEL expression to be evaluated. If the Expression + // returns a true value, the function will render the resources + Expression string `json:"expression"` +} diff --git a/input/v1beta1/resources.go b/input/v1beta1/resources.go index c86f447..247ca01 100644 --- a/input/v1beta1/resources.go +++ b/input/v1beta1/resources.go @@ -20,6 +20,9 @@ type Resources struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` + // Condition defines a CEL condition whether this function will render + Condition *ConditionSpec `json:"condition,omitempty"` + // PatchSets define a named set of patches that may be included by any // resource. PatchSets cannot themselves refer to other PatchSets. // +optional diff --git a/input/v1beta1/resources_common.go b/input/v1beta1/resources_common.go index abed367..031a5ed 100644 --- a/input/v1beta1/resources_common.go +++ b/input/v1beta1/resources_common.go @@ -47,6 +47,9 @@ type ComposedTemplate struct { // +optional Base *runtime.RawExtension `json:"base,omitempty"` + // Condition defines a CEL condition whether this function will render + Condition *ConditionSpec `json:"condition,omitempty"` + // Patches to and from the composed resource. // +optional Patches []Patch `json:"patches,omitempty"` diff --git a/input/v1beta1/zz_generated.deepcopy.go b/input/v1beta1/zz_generated.deepcopy.go index fa224c5..4cec4a8 100644 --- a/input/v1beta1/zz_generated.deepcopy.go +++ b/input/v1beta1/zz_generated.deepcopy.go @@ -90,6 +90,21 @@ func (in *ComposedTemplate) DeepCopy() *ComposedTemplate { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConditionSpec) DeepCopyInto(out *ConditionSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionSpec. +func (in *ConditionSpec) DeepCopy() *ConditionSpec { + if in == nil { + return nil + } + out := new(ConditionSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConnectionDetail) DeepCopyInto(out *ConnectionDetail) { *out = *in @@ -407,6 +422,11 @@ func (in *Resources) DeepCopyInto(out *Resources) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Condition != nil { + in, out := &in.Condition, &out.Condition + *out = new(ConditionSpec) + **out = **in + } if in.PatchSets != nil { in, out := &in.PatchSets, &out.PatchSets *out = make([]PatchSet, len(*in)) diff --git a/package/crossplane.yaml b/package/crossplane.yaml index 866d2d3..48215e0 100644 --- a/package/crossplane.yaml +++ b/package/crossplane.yaml @@ -2,17 +2,17 @@ apiVersion: meta.pkg.crossplane.io/v1beta1 kind: Function metadata: - name: function-patch-and-transform + name: function-conditional-patch-and-transform annotations: meta.crossplane.io/maintainer: Crossplane Maintainers - meta.crossplane.io/source: github.com/crossplane-contrib/function-patch-and-transform + meta.crossplane.io/source: github.com/stevendborrelli/function-conditional-patch-and-transform meta.crossplane.io/license: Apache-2.0 - meta.crossplane.io/description: A patch & transform composition function + meta.crossplane.io/description: A patch & transform composition function that supports conditionals meta.crossplane.io/readme: | - This composition function does everything Crossplane's built-in - [patch & transform](https://docs.crossplane.io/latest/concepts/patch-and-transform/) - composition does. Instead of specifying `spec.resources` in your - Composition, you can use this function. See the - [README](https://github.com/crossplane-contrib/function-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 + of individual resources. + See the + [README](https://github.com/stevendborrelli/function-conditional-patch-and-transform) for examples and documentation. spec: {} diff --git a/package/input/pt.fn.crossplane.io_resources.yaml b/package/input/pt.fn.crossplane.io_resources.yaml index 9751e43..4dc2796 100644 --- a/package/input/pt.fn.crossplane.io_resources.yaml +++ b/package/input/pt.fn.crossplane.io_resources.yaml @@ -26,6 +26,18 @@ spec: 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: Condition defines a CEL condition whether this function will + render + properties: + expression: + description: Expression is the CEL expression to be evaluated. If + the Expression returns a true value, the function will render the + resources + type: string + required: + - expression + type: object environment: description: "Environment represents the Composition environment. \n THIS IS AN ALPHA FIELD. Do not use it in production. It may be changed or diff --git a/patches.go b/patches.go index 3ac372f..565369d 100644 --- a/patches.go +++ b/patches.go @@ -10,7 +10,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) const ( diff --git a/patches_test.go b/patches_test.go index b6f6986..05f77d0 100644 --- a/patches_test.go +++ b/patches_test.go @@ -17,7 +17,7 @@ import ( "github.com/crossplane/function-sdk-go/resource/composite" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) func TestPatchApply(t *testing.T) { diff --git a/ready.go b/ready.go index bb0dc8a..dd6ddd4 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/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) // Error strings diff --git a/ready_test.go b/ready_test.go index 5d3bad8..bf0b8c9 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/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) var _ ReadinessChecker = ReadinessCheckerFn(IsReady) diff --git a/render.go b/render.go index e1669b2..a2dd8cd 100644 --- a/render.go +++ b/render.go @@ -9,7 +9,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) // Error strings diff --git a/transforms.go b/transforms.go index c1a20c5..3d9d139 100644 --- a/transforms.go +++ b/transforms.go @@ -19,7 +19,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) const ( diff --git a/transforms_test.go b/transforms_test.go index be328e1..bc42130 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/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) func TestMapResolve(t *testing.T) { diff --git a/validate.go b/validate.go index 417a326..9a1d451 100644 --- a/validate.go +++ b/validate.go @@ -6,7 +6,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" - "github.com/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) // WrapFieldError wraps the given field.Error adding the given field.Path as root of the Field. diff --git a/validate_test.go b/validate_test.go index 69e7c52..23af3be 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/crossplane-contrib/function-patch-and-transform/input/v1beta1" + "github.com/stevendborrelli/function-conditional-patch-and-transform/input/v1beta1" ) func TestValidateReadinessCheck(t *testing.T) {