diff --git a/pkg/commands/assert/command.go b/pkg/commands/assert/command.go index a74f71356..55a2e9832 100644 --- a/pkg/commands/assert/command.go +++ b/pkg/commands/assert/command.go @@ -6,7 +6,6 @@ import ( "io" "time" - "github.com/jmespath-community/go-jmespath/pkg/binding" "github.com/kyverno/chainsaw/pkg/apis/v1alpha1" ctrlClient "github.com/kyverno/chainsaw/pkg/client" tclient "github.com/kyverno/chainsaw/pkg/client/testing" @@ -135,6 +134,6 @@ func runE(opts options, cmd *cobra.Command, client ctrlClient.Client, namespacer func assert(opts options, client ctrlClient.Client, resource unstructured.Unstructured, namespacer nspacer.Namespacer) error { ctx, cancel := context.WithTimeout(context.Background(), opts.timeout.Duration) defer cancel() - op := opassert.New(client, resource, namespacer, binding.NewBindings(), false) - return op.Exec(ctx) + op := opassert.New(client, resource, namespacer, false) + return op.Exec(ctx, nil) } diff --git a/pkg/runner/operations/apply/operation.go b/pkg/runner/operations/apply/operation.go index 5fcc14216..5603bfd6a 100644 --- a/pkg/runner/operations/apply/operation.go +++ b/pkg/runner/operations/apply/operation.go @@ -26,7 +26,6 @@ type operation struct { base unstructured.Unstructured namespacer namespacer.Namespacer cleaner cleanup.Cleaner - bindings binding.Bindings template bool expect []v1alpha1.Expectation } @@ -36,25 +35,23 @@ func New( obj unstructured.Unstructured, namespacer namespacer.Namespacer, cleaner cleanup.Cleaner, - bindings binding.Bindings, template bool, expect []v1alpha1.Expectation, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ client: client, base: obj, namespacer: namespacer, cleaner: cleaner, - bindings: bindings, template: template, expect: expect, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } obj := o.base logger := internal.GetLogger(ctx, &obj) defer func() { @@ -64,7 +61,7 @@ func (o *operation) Exec(ctx context.Context) (err error) { template := v1alpha1.Any{ Value: obj.UnstructuredContent(), } - if merged, err := mutate.Merge(ctx, obj, o.bindings, template); err != nil { + if merged, err := mutate.Merge(ctx, obj, bindings, template); err != nil { return err } else { obj = merged @@ -74,13 +71,13 @@ func (o *operation) Exec(ctx context.Context) (err error) { return err } internal.LogStart(logger, logging.Apply) - return o.execute(ctx, obj) + return o.execute(ctx, bindings, obj) } -func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var lastErr error err := wait.PollUntilContextCancel(ctx, internal.PollInterval, false, func(ctx context.Context) (bool, error) { - lastErr = o.tryApplyResource(ctx, obj) + lastErr = o.tryApplyResource(ctx, bindings, obj) // TODO: determine if the error can be retried return lastErr == nil, nil }) @@ -93,20 +90,20 @@ func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) return err } -func (o *operation) tryApplyResource(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) tryApplyResource(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var actual unstructured.Unstructured actual.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) err := o.client.Get(ctx, client.ObjectKey(&obj), &actual) if err == nil { - return o.updateResource(ctx, &actual, obj) + return o.updateResource(ctx, bindings, &actual, obj) } if kerrors.IsNotFound(err) { - return o.createResource(ctx, obj) + return o.createResource(ctx, bindings, obj) } return err } -func (o *operation) updateResource(ctx context.Context, actual *unstructured.Unstructured, obj unstructured.Unstructured) error { +func (o *operation) updateResource(ctx context.Context, bindings binding.Bindings, actual *unstructured.Unstructured, obj unstructured.Unstructured) error { patched, err := client.PatchObject(actual, &obj) if err != nil { return err @@ -115,19 +112,18 @@ func (o *operation) updateResource(ctx context.Context, actual *unstructured.Uns if err != nil { return err } - return o.handleCheck(ctx, obj, o.client.Patch(ctx, actual, ctrlclient.RawPatch(types.MergePatchType, bytes))) + return o.handleCheck(ctx, bindings, obj, o.client.Patch(ctx, actual, ctrlclient.RawPatch(types.MergePatchType, bytes))) } -func (o *operation) createResource(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) createResource(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { err := o.client.Create(ctx, &obj) if err == nil && o.cleaner != nil { o.cleaner(obj, o.client) } - return o.handleCheck(ctx, obj, err) + return o.handleCheck(ctx, bindings, obj, err) } -func (o *operation) handleCheck(ctx context.Context, obj unstructured.Unstructured, err error) error { - bindings := o.bindings +func (o *operation) handleCheck(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured, err error) error { if err == nil { bindings = bindings.Register("$error", binding.NewBinding(nil)) } else { diff --git a/pkg/runner/operations/apply/operation_test.go b/pkg/runner/operations/apply/operation_test.go index 2b74e0f23..1bbaf9441 100644 --- a/pkg/runner/operations/apply/operation_test.go +++ b/pkg/runner/operations/apply/operation_test.go @@ -298,11 +298,10 @@ func Test_apply(t *testing.T) { tt.object, nil, nil, - nil, false, tt.expect, ) - err := operation.Exec(ctx) + err := operation.Exec(ctx, nil) if tt.expectedErr != nil { assert.EqualError(t, err, tt.expectedErr.Error()) } else { diff --git a/pkg/runner/operations/assert/operation.go b/pkg/runner/operations/assert/operation.go index 75c3b4958..5af630fd9 100644 --- a/pkg/runner/operations/assert/operation.go +++ b/pkg/runner/operations/assert/operation.go @@ -24,7 +24,6 @@ type operation struct { client client.Client base unstructured.Unstructured namespacer namespacer.Namespacer - bindings binding.Bindings template bool } @@ -32,29 +31,27 @@ func New( client client.Client, expected unstructured.Unstructured, namespacer namespacer.Namespacer, - bindings binding.Bindings, template bool, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ client: client, base: expected, namespacer: namespacer, - bindings: bindings, template: template, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } obj := o.base logger := internal.GetLogger(ctx, &obj) defer func() { internal.LogEnd(logger, logging.Assert, err) }() if o.template { - if err := template.ResourceRef(ctx, &obj, o.bindings); err != nil { + if err := template.ResourceRef(ctx, &obj, bindings); err != nil { return err } } @@ -64,12 +61,11 @@ func (o *operation) Exec(ctx context.Context) (err error) { } } internal.LogStart(logger, logging.Assert) - return o.execute(ctx, obj) + return o.execute(ctx, bindings, obj) } -func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var lastErrs []error - bindings := o.bindings err := wait.PollUntilContextCancel(ctx, internal.PollInterval, false, func(ctx context.Context) (_ bool, err error) { var errs []error defer func() { diff --git a/pkg/runner/operations/assert/operation_test.go b/pkg/runner/operations/assert/operation_test.go index fd3520427..e8ab2bf82 100644 --- a/pkg/runner/operations/assert/operation_test.go +++ b/pkg/runner/operations/assert/operation_test.go @@ -316,11 +316,10 @@ func Test_operationAssert(t *testing.T) { tt.client, tt.expected, nspacer, - nil, false, ) logger := &tlogging.FakeLogger{} - err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t)) + err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t), nil) if tt.expectErr { assert.NotNil(t, err) } else { diff --git a/pkg/runner/operations/command/operation.go b/pkg/runner/operations/command/operation.go index d1b9d2cab..2b382e302 100644 --- a/pkg/runner/operations/command/operation.go +++ b/pkg/runner/operations/command/operation.go @@ -23,7 +23,6 @@ type operation struct { command v1alpha1.Command basePath string namespace string - bindings binding.Bindings cfg *rest.Config } @@ -31,22 +30,20 @@ func New( command v1alpha1.Command, basePath string, namespace string, - bindings binding.Bindings, cfg *rest.Config, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ command: command, basePath: basePath, namespace: namespace, - bindings: bindings, cfg: cfg, } } -func (o *operation) Exec(ctx context.Context) (_err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (_err error) { + if bindings == nil { + bindings = binding.NewBindings() + } logger := internal.GetLogger(ctx, nil) defer func() { internal.LogEnd(logger, logging.Command, _err) @@ -59,7 +56,7 @@ func (o *operation) Exec(ctx context.Context) (_err error) { return err } internal.LogStart(logger, logging.Command, logging.Section("COMMAND", cmd.String())) - return o.execute(ctx, cmd) + return o.execute(ctx, bindings, cmd) } func (o *operation) createCommand(ctx context.Context) (*exec.Cmd, context.CancelFunc, error) { @@ -99,7 +96,7 @@ func (o *operation) createCommand(ctx context.Context) (*exec.Cmd, context.Cance return cmd, cancel, nil } -func (o *operation) execute(ctx context.Context, cmd *exec.Cmd) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, cmd *exec.Cmd) error { logger := logging.FromContext(ctx) var output internal.CommandOutput if !o.command.SkipLogOutput { @@ -115,7 +112,7 @@ func (o *operation) execute(ctx context.Context, cmd *exec.Cmd) error { if o.command.Check == nil || o.command.Check.Value == nil { return err } - bindings := o.bindings.Register("$stdout", binding.NewBinding(output.Out())) + bindings = bindings.Register("$stdout", binding.NewBinding(output.Out())) bindings = bindings.Register("$stderr", binding.NewBinding(output.Err())) if err == nil { bindings = bindings.Register("$error", binding.NewBinding(nil)) diff --git a/pkg/runner/operations/command/operation_test.go b/pkg/runner/operations/command/operation_test.go index bf24a03fd..e1317effa 100644 --- a/pkg/runner/operations/command/operation_test.go +++ b/pkg/runner/operations/command/operation_test.go @@ -107,9 +107,8 @@ func Test_operationCommand(t *testing.T) { tt.basePath, tt.namespace, nil, - nil, ) - err := operation.Exec(ctx) + err := operation.Exec(ctx, nil) if tt.wantErr { assert.Error(t, err) } else { diff --git a/pkg/runner/operations/create/operation.go b/pkg/runner/operations/create/operation.go index 51560991c..09bce4ebe 100644 --- a/pkg/runner/operations/create/operation.go +++ b/pkg/runner/operations/create/operation.go @@ -24,7 +24,6 @@ type operation struct { base unstructured.Unstructured namespacer namespacer.Namespacer cleaner cleanup.Cleaner - bindings binding.Bindings template bool expect []v1alpha1.Expectation } @@ -34,25 +33,23 @@ func New( obj unstructured.Unstructured, namespacer namespacer.Namespacer, cleaner cleanup.Cleaner, - bindings binding.Bindings, template bool, expect []v1alpha1.Expectation, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ client: client, base: obj, namespacer: namespacer, cleaner: cleaner, - bindings: bindings, template: template, expect: expect, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } obj := o.base logger := internal.GetLogger(ctx, &obj) defer func() { @@ -61,7 +58,7 @@ func (o *operation) Exec(ctx context.Context) (err error) { selfModifier := v1alpha1.Any{ Value: obj.UnstructuredContent(), } - if merged, err := mutate.Merge(ctx, obj, o.bindings, selfModifier); err != nil { + if merged, err := mutate.Merge(ctx, obj, bindings, selfModifier); err != nil { return err } else { obj = merged @@ -70,13 +67,13 @@ func (o *operation) Exec(ctx context.Context) (err error) { return err } internal.LogStart(logger, logging.Create) - return o.execute(ctx, obj) + return o.execute(ctx, bindings, obj) } -func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var lastErr error err := wait.PollUntilContextCancel(ctx, internal.PollInterval, false, func(ctx context.Context) (bool, error) { - lastErr = o.tryCreateResource(ctx, obj) + lastErr = o.tryCreateResource(ctx, bindings, obj) // TODO: determine if the error can be retried return lastErr == nil, nil }) @@ -90,7 +87,7 @@ func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) } // TODO: could be replaced by checking the already exists error -func (o *operation) tryCreateResource(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) tryCreateResource(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var actual unstructured.Unstructured actual.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) err := o.client.Get(ctx, client.ObjectKey(&obj), &actual) @@ -98,21 +95,20 @@ func (o *operation) tryCreateResource(ctx context.Context, obj unstructured.Unst return errors.New("the resource already exists in the cluster") } if kerrors.IsNotFound(err) { - return o.createResource(ctx, obj) + return o.createResource(ctx, bindings, obj) } return err } -func (o *operation) createResource(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) createResource(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { err := o.client.Create(ctx, &obj) if err == nil && o.cleaner != nil { o.cleaner(obj, o.client) } - return o.handleCheck(ctx, obj, err) + return o.handleCheck(ctx, bindings, obj, err) } -func (o *operation) handleCheck(ctx context.Context, obj unstructured.Unstructured, err error) error { - bindings := o.bindings +func (o *operation) handleCheck(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured, err error) error { if err == nil { bindings = bindings.Register("$error", binding.NewBinding(nil)) } else { diff --git a/pkg/runner/operations/create/operation_test.go b/pkg/runner/operations/create/operation_test.go index fe7f3a393..fe8f20c12 100644 --- a/pkg/runner/operations/create/operation_test.go +++ b/pkg/runner/operations/create/operation_test.go @@ -223,11 +223,10 @@ func Test_create(t *testing.T) { tt.object, nil, tt.cleaner, - nil, false, tt.expect, ) - err := operation.Exec(ctx) + err := operation.Exec(ctx, nil) if tt.expectedErr != nil { assert.EqualError(t, err, tt.expectedErr.Error()) } else { diff --git a/pkg/runner/operations/delete/operation.go b/pkg/runner/operations/delete/operation.go index 628fe6644..fde2a96c1 100644 --- a/pkg/runner/operations/delete/operation.go +++ b/pkg/runner/operations/delete/operation.go @@ -22,7 +22,6 @@ type operation struct { client client.Client base unstructured.Unstructured namespacer namespacer.Namespacer - bindings binding.Bindings template bool expect []v1alpha1.Expectation } @@ -31,24 +30,22 @@ func New( client client.Client, obj unstructured.Unstructured, namespacer namespacer.Namespacer, - bindings binding.Bindings, template bool, expect ...v1alpha1.Expectation, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ client: client, base: obj, namespacer: namespacer, - bindings: bindings, template: template, expect: expect, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } obj := o.base logger := internal.GetLogger(ctx, &obj) defer func() { @@ -58,7 +55,7 @@ func (o *operation) Exec(ctx context.Context) (err error) { template := v1alpha1.Any{ Value: obj.UnstructuredContent(), } - if merged, err := mutate.Merge(ctx, obj, o.bindings, template); err != nil { + if merged, err := mutate.Merge(ctx, obj, bindings, template); err != nil { return err } else { obj = merged @@ -68,15 +65,15 @@ func (o *operation) Exec(ctx context.Context) (err error) { return err } internal.LogStart(logger, logging.Delete) - return o.execute(ctx, obj) + return o.execute(ctx, bindings, obj) } -func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { resources, err := o.getResourcesToDelete(ctx, obj) if err != nil { return err } - return o.deleteResources(ctx, resources...) + return o.deleteResources(ctx, bindings, resources...) } func (o *operation) getResourcesToDelete(ctx context.Context, obj unstructured.Unstructured) ([]unstructured.Unstructured, error) { @@ -90,7 +87,7 @@ func (o *operation) getResourcesToDelete(ctx context.Context, obj unstructured.U return resources, nil } -func (o *operation) deleteResources(ctx context.Context, resources ...unstructured.Unstructured) error { +func (o *operation) deleteResources(ctx context.Context, bindings binding.Bindings, resources ...unstructured.Unstructured) error { var errs []error var deleted []unstructured.Unstructured for _, resource := range resources { @@ -100,7 +97,7 @@ func (o *operation) deleteResources(ctx context.Context, resources ...unstructur deleted = append(deleted, resource) } // check if the result was the expected one - if err := o.handleCheck(ctx, resource, err); err != nil { + if err := o.handleCheck(ctx, bindings, resource, err); err != nil { errs = append(errs, err) } } @@ -138,8 +135,7 @@ func (o *operation) waitForDeletion(ctx context.Context, resource unstructured.U }) } -func (o *operation) handleCheck(ctx context.Context, resource unstructured.Unstructured, err error) error { - bindings := o.bindings +func (o *operation) handleCheck(ctx context.Context, bindings binding.Bindings, resource unstructured.Unstructured, err error) error { if err == nil { bindings = bindings.Register("$error", binding.NewBinding(nil)) } else { diff --git a/pkg/runner/operations/delete/operation_test.go b/pkg/runner/operations/delete/operation_test.go index 516ac22e5..ea4f3c6a2 100644 --- a/pkg/runner/operations/delete/operation_test.go +++ b/pkg/runner/operations/delete/operation_test.go @@ -170,12 +170,11 @@ func Test_operationDelete(t *testing.T) { tt.client, tt.object, nspacer, - nil, false, tt.expect..., ) logger := &tlogging.FakeLogger{} - err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t)) + err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t), nil) if tt.expectedErr != nil { assert.EqualError(t, err, tt.expectedErr.Error()) } else { diff --git a/pkg/runner/operations/error/operation.go b/pkg/runner/operations/error/operation.go index 338340731..4fea7c8cc 100644 --- a/pkg/runner/operations/error/operation.go +++ b/pkg/runner/operations/error/operation.go @@ -23,7 +23,6 @@ type operation struct { client client.Client base unstructured.Unstructured namespacer namespacer.Namespacer - bindings binding.Bindings template bool } @@ -31,29 +30,27 @@ func New( client client.Client, expected unstructured.Unstructured, namespacer namespacer.Namespacer, - bindings binding.Bindings, template bool, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ client: client, base: expected, namespacer: namespacer, - bindings: bindings, template: template, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } obj := o.base logger := internal.GetLogger(ctx, &obj) defer func() { internal.LogEnd(logger, logging.Error, err) }() if o.template { - if err := template.ResourceRef(ctx, &obj, o.bindings); err != nil { + if err := template.ResourceRef(ctx, &obj, bindings); err != nil { return err } } @@ -63,12 +60,11 @@ func (o *operation) Exec(ctx context.Context) (err error) { } } internal.LogStart(logger, logging.Error) - return o.execute(ctx, obj) + return o.execute(ctx, bindings, obj) } -func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var lastErrs []error - bindings := o.bindings err := wait.PollUntilContextCancel(ctx, internal.PollInterval, false, func(ctx context.Context) (_ bool, err error) { var errs []error defer func() { diff --git a/pkg/runner/operations/error/operation_test.go b/pkg/runner/operations/error/operation_test.go index b4a3f4302..8b260a8d9 100644 --- a/pkg/runner/operations/error/operation_test.go +++ b/pkg/runner/operations/error/operation_test.go @@ -213,11 +213,10 @@ func Test_operationError(t *testing.T) { tt.client, tt.expected, nspacer, - nil, false, ) logger := &tlogging.FakeLogger{} - err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t)) + err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t), nil) if tt.expectedErr != nil { assert.EqualError(t, err, tt.expectedErr.Error()) } else { diff --git a/pkg/runner/operations/operation.go b/pkg/runner/operations/operation.go index c1f42001f..209031d89 100644 --- a/pkg/runner/operations/operation.go +++ b/pkg/runner/operations/operation.go @@ -2,8 +2,10 @@ package operations import ( "context" + + "github.com/jmespath-community/go-jmespath/pkg/binding" ) type Operation interface { - Exec(ctx context.Context) error + Exec(context.Context, binding.Bindings) error } diff --git a/pkg/runner/operations/patch/operation.go b/pkg/runner/operations/patch/operation.go index bc15ba7f0..fe7455a05 100644 --- a/pkg/runner/operations/patch/operation.go +++ b/pkg/runner/operations/patch/operation.go @@ -23,7 +23,6 @@ type operation struct { client client.Client base unstructured.Unstructured namespacer namespacer.Namespacer - bindings binding.Bindings template bool expect []v1alpha1.Expectation } @@ -32,24 +31,22 @@ func New( client client.Client, obj unstructured.Unstructured, namespacer namespacer.Namespacer, - bindings binding.Bindings, template bool, expect []v1alpha1.Expectation, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ client: client, base: obj, namespacer: namespacer, - bindings: bindings, template: template, expect: expect, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } obj := o.base logger := internal.GetLogger(ctx, &obj) defer func() { @@ -58,7 +55,7 @@ func (o *operation) Exec(ctx context.Context) (err error) { selfModifier := v1alpha1.Any{ Value: obj.UnstructuredContent(), } - if merged, err := mutate.Merge(ctx, obj, o.bindings, selfModifier); err != nil { + if merged, err := mutate.Merge(ctx, obj, bindings, selfModifier); err != nil { return err } else { obj = merged @@ -67,13 +64,13 @@ func (o *operation) Exec(ctx context.Context) (err error) { return err } internal.LogStart(logger, logging.Patch) - return o.execute(ctx, obj) + return o.execute(ctx, bindings, obj) } -func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var lastErr error err := wait.PollUntilContextCancel(ctx, internal.PollInterval, false, func(ctx context.Context) (bool, error) { - lastErr = o.tryPatchResource(ctx, obj) + lastErr = o.tryPatchResource(ctx, bindings, obj) // TODO: determine if the error can be retried return lastErr == nil, nil }) @@ -86,17 +83,17 @@ func (o *operation) execute(ctx context.Context, obj unstructured.Unstructured) return err } -func (o *operation) tryPatchResource(ctx context.Context, obj unstructured.Unstructured) error { +func (o *operation) tryPatchResource(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured) error { var actual unstructured.Unstructured actual.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) err := o.client.Get(ctx, client.ObjectKey(&obj), &actual) if err != nil { return err } - return o.updateResource(ctx, &actual, obj) + return o.updateResource(ctx, bindings, &actual, obj) } -func (o *operation) updateResource(ctx context.Context, actual *unstructured.Unstructured, obj unstructured.Unstructured) error { +func (o *operation) updateResource(ctx context.Context, bindings binding.Bindings, actual *unstructured.Unstructured, obj unstructured.Unstructured) error { patched, err := client.PatchObject(actual, &obj) if err != nil { return err @@ -105,11 +102,10 @@ func (o *operation) updateResource(ctx context.Context, actual *unstructured.Uns if err != nil { return err } - return o.handleCheck(ctx, obj, o.client.Patch(ctx, actual, ctrlclient.RawPatch(types.MergePatchType, bytes))) + return o.handleCheck(ctx, bindings, obj, o.client.Patch(ctx, actual, ctrlclient.RawPatch(types.MergePatchType, bytes))) } -func (o *operation) handleCheck(ctx context.Context, obj unstructured.Unstructured, err error) error { - bindings := o.bindings +func (o *operation) handleCheck(ctx context.Context, bindings binding.Bindings, obj unstructured.Unstructured, err error) error { if err == nil { bindings = bindings.Register("$error", binding.NewBinding(nil)) } else { diff --git a/pkg/runner/operations/patch/operation_test.go b/pkg/runner/operations/patch/operation_test.go index 8c7d288d2..4d0852b26 100644 --- a/pkg/runner/operations/patch/operation_test.go +++ b/pkg/runner/operations/patch/operation_test.go @@ -212,11 +212,10 @@ func Test_create(t *testing.T) { tt.client, tt.object, nil, - nil, false, tt.expect, ) - err := operation.Exec(ctx) + err := operation.Exec(ctx, nil) if tt.expectedErr != nil { assert.EqualError(t, err, tt.expectedErr.Error()) } else { diff --git a/pkg/runner/operations/script/operation.go b/pkg/runner/operations/script/operation.go index ab5d1d2be..be1741e48 100644 --- a/pkg/runner/operations/script/operation.go +++ b/pkg/runner/operations/script/operation.go @@ -22,7 +22,6 @@ type operation struct { script v1alpha1.Script basePath string namespace string - bindings binding.Bindings cfg *rest.Config } @@ -30,22 +29,20 @@ func New( script v1alpha1.Script, basePath string, namespace string, - bindings binding.Bindings, cfg *rest.Config, ) operations.Operation { - if bindings == nil { - bindings = binding.NewBindings() - } return &operation{ script: script, basePath: basePath, namespace: namespace, - bindings: bindings, cfg: cfg, } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, bindings binding.Bindings) (err error) { + if bindings == nil { + bindings = binding.NewBindings() + } logger := internal.GetLogger(ctx, nil) defer func() { internal.LogEnd(logger, logging.Script, err) @@ -58,7 +55,7 @@ func (o *operation) Exec(ctx context.Context) (err error) { return err } internal.LogStart(logger, logging.Script, logging.Section("COMMAND", cmd.String())) - return o.execute(ctx, cmd) + return o.execute(ctx, bindings, cmd) } func (o *operation) createCommand(ctx context.Context) (*exec.Cmd, context.CancelFunc, error) { @@ -95,7 +92,7 @@ func (o *operation) createCommand(ctx context.Context) (*exec.Cmd, context.Cance return cmd, cancel, nil } -func (o *operation) execute(ctx context.Context, cmd *exec.Cmd) error { +func (o *operation) execute(ctx context.Context, bindings binding.Bindings, cmd *exec.Cmd) error { logger := internal.GetLogger(ctx, nil) var output internal.CommandOutput if !o.script.SkipLogOutput { @@ -111,7 +108,7 @@ func (o *operation) execute(ctx context.Context, cmd *exec.Cmd) error { if o.script.Check == nil || o.script.Check.Value == nil { return err } - bindings := o.bindings.Register("$stdout", binding.NewBinding(output.Out())) + bindings = bindings.Register("$stdout", binding.NewBinding(output.Out())) bindings = bindings.Register("$stderr", binding.NewBinding(output.Err())) if err == nil { bindings = bindings.Register("$error", binding.NewBinding(nil)) diff --git a/pkg/runner/operations/script/operation_test.go b/pkg/runner/operations/script/operation_test.go index ede090eb1..8fca6f846 100644 --- a/pkg/runner/operations/script/operation_test.go +++ b/pkg/runner/operations/script/operation_test.go @@ -101,9 +101,8 @@ func Test_operationScript(t *testing.T) { tt.basePath, tt.namespace, nil, - nil, ) - err := operation.Exec(ctx) + err := operation.Exec(ctx, nil) if tt.wantErr { assert.Error(t, err) } else { diff --git a/pkg/runner/operations/sleep/operation.go b/pkg/runner/operations/sleep/operation.go index 6802b1da4..f02a5b339 100644 --- a/pkg/runner/operations/sleep/operation.go +++ b/pkg/runner/operations/sleep/operation.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/jmespath-community/go-jmespath/pkg/binding" "github.com/kyverno/chainsaw/pkg/apis/v1alpha1" "github.com/kyverno/chainsaw/pkg/runner/logging" "github.com/kyverno/chainsaw/pkg/runner/operations" @@ -20,7 +21,7 @@ func New(duration v1alpha1.Sleep) operations.Operation { } } -func (o *operation) Exec(ctx context.Context) (err error) { +func (o *operation) Exec(ctx context.Context, _ binding.Bindings) (err error) { logger := internal.GetLogger(ctx, nil) defer func() { internal.LogEnd(logger, logging.Sleep, err) diff --git a/pkg/runner/operations/sleep/operation_test.go b/pkg/runner/operations/sleep/operation_test.go index 7eb6ce723..e077bd265 100644 --- a/pkg/runner/operations/sleep/operation_test.go +++ b/pkg/runner/operations/sleep/operation_test.go @@ -37,7 +37,7 @@ func Test_operation_Exec(t *testing.T) { tt.sleep, ) logger := &tlogging.FakeLogger{} - err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t)) + err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t), nil) assert.NoError(t, err) assert.Equal(t, tt.expectedLogs, logger.Logs) }) diff --git a/pkg/runner/operations/testing/mock.go b/pkg/runner/operations/testing/mock.go index c83077af1..5e8d7c1c5 100644 --- a/pkg/runner/operations/testing/mock.go +++ b/pkg/runner/operations/testing/mock.go @@ -1,11 +1,15 @@ package testing -import "context" +import ( + "context" + + "github.com/jmespath-community/go-jmespath/pkg/binding" +) type MockOperation struct { - ExecFn func(ctx context.Context) error + ExecFn func(context.Context, binding.Bindings) error } -func (m MockOperation) Exec(ctx context.Context) error { - return m.ExecFn(ctx) +func (m MockOperation) Exec(ctx context.Context, bindings binding.Bindings) error { + return m.ExecFn(ctx, bindings) } diff --git a/pkg/runner/processors/bindings.go b/pkg/runner/processors/bindings.go new file mode 100644 index 000000000..17fe6ad5f --- /dev/null +++ b/pkg/runner/processors/bindings.go @@ -0,0 +1,48 @@ +package processors + +import ( + "context" + "fmt" + "regexp" + "strings" + + "github.com/jmespath-community/go-jmespath/pkg/binding" + "github.com/kyverno/chainsaw/pkg/apis/v1alpha1" + mutation "github.com/kyverno/chainsaw/pkg/mutate" + "github.com/kyverno/chainsaw/pkg/runner/functions" + "github.com/kyverno/kyverno-json/pkg/engine/template" + "k8s.io/apimachinery/pkg/util/sets" +) + +var ( + identifier = regexp.MustCompile(`^\w+$`) + forbiddenNames = []string{"namespace", "client", "error", "values", "stdout", "stderr"} + forbidden = sets.New(forbiddenNames...) +) + +func registerBindings(ctx context.Context, bindings binding.Bindings, variables ...v1alpha1.Binding) (binding.Bindings, error) { + if bindings == nil { + bindings = binding.NewBindings() + } + for _, variable := range variables { + if err := checkBindingName(variable.Name); err != nil { + return bindings, err + } + patched, err := mutation.Mutate(ctx, nil, mutation.Parse(ctx, variable.Value.Value), nil, bindings, template.WithFunctionCaller(functions.Caller)) + if err != nil { + return bindings, err + } + bindings = bindings.Register("$"+variable.Name, binding.NewBinding(patched)) + } + return bindings, nil +} + +func checkBindingName(name string) error { + if forbidden.Has(name) { + return fmt.Errorf("binding name is forbidden (%s), it must not be (%s)", name, strings.Join(forbiddenNames, ", ")) + } + if !identifier.MatchString(name) { + return fmt.Errorf("invalid binding name %s", name) + } + return nil +} diff --git a/pkg/runner/processors/cleaner.go b/pkg/runner/processors/cleaner.go index 037de4d12..dd0cbb9ce 100644 --- a/pkg/runner/processors/cleaner.go +++ b/pkg/runner/processors/cleaner.go @@ -25,11 +25,13 @@ func newCleaner(namespacer namespacer.Namespacer, delay *metav1.Duration) *clean } func (c *cleaner) register(obj unstructured.Unstructured, client client.Client, timeout *time.Duration) { - c.operations = append(c.operations, operation{ - continueOnError: true, - timeout: timeout, - operation: opdelete.New(client, obj, c.namespacer, nil, false), - }) + c.operations = append(c.operations, newOperation( + true, + timeout, + opdelete.New(client, obj, c.namespacer, false), + nil, + nil, + )) } func (c *cleaner) run(ctx context.Context) { diff --git a/pkg/runner/processors/cleaner_test.go b/pkg/runner/processors/cleaner_test.go index ebc88a3ed..29fd991fe 100644 --- a/pkg/runner/processors/cleaner_test.go +++ b/pkg/runner/processors/cleaner_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/jmespath-community/go-jmespath/pkg/binding" fake "github.com/kyverno/chainsaw/pkg/client/testing" "github.com/kyverno/chainsaw/pkg/runner/namespacer" mock "github.com/kyverno/chainsaw/pkg/runner/operations/testing" @@ -71,7 +72,7 @@ func Test_Cleaner_Run(t *testing.T) { continueOnError: true, timeout: nil, operation: mock.MockOperation{ - ExecFn: func(ctx context.Context) error { + ExecFn: func(_ context.Context, _ binding.Bindings) error { return nil }, }, diff --git a/pkg/runner/processors/operation.go b/pkg/runner/processors/operation.go index 26a402808..0230d7e7c 100644 --- a/pkg/runner/processors/operation.go +++ b/pkg/runner/processors/operation.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/jmespath-community/go-jmespath/pkg/binding" + "github.com/kyverno/chainsaw/pkg/apis/v1alpha1" "github.com/kyverno/chainsaw/pkg/report" "github.com/kyverno/chainsaw/pkg/runner/operations" "github.com/kyverno/chainsaw/pkg/testing" @@ -14,6 +16,26 @@ type operation struct { timeout *time.Duration operation operations.Operation operationReport *report.OperationReport + bindings binding.Bindings + variables []v1alpha1.Binding +} + +func newOperation( + continueOnError bool, + timeout *time.Duration, + op operations.Operation, + operationReport *report.OperationReport, + bindings binding.Bindings, + variables ...v1alpha1.Binding, +) operation { + return operation{ + continueOnError: continueOnError, + timeout: timeout, + operation: op, + operationReport: operationReport, + bindings: bindings, + variables: variables, + } } func (o operation) execute(ctx context.Context) { @@ -22,7 +44,16 @@ func (o operation) execute(ctx context.Context) { ctx = toCtx defer cancel() } - if err := o.operation.Exec(ctx); err != nil { + bindings, err := registerBindings(ctx, o.bindings, o.variables...) + if err != nil { + t := testing.FromContext(ctx) + if o.continueOnError { + t.Fail() + } else { + t.FailNow() + } + } + if err := o.operation.Exec(ctx, bindings); err != nil { t := testing.FromContext(ctx) if o.operationReport != nil { o.operationReport.MarkOperationEnd(false, err.Error()) diff --git a/pkg/runner/processors/operation_test.go b/pkg/runner/processors/operation_test.go index 5ae6f6563..4152d55b2 100644 --- a/pkg/runner/processors/operation_test.go +++ b/pkg/runner/processors/operation_test.go @@ -5,6 +5,7 @@ import ( "errors" "time" + "github.com/jmespath-community/go-jmespath/pkg/binding" "github.com/kyverno/chainsaw/pkg/report" "github.com/kyverno/chainsaw/pkg/runner/operations" mock "github.com/kyverno/chainsaw/pkg/runner/operations/testing" @@ -24,7 +25,7 @@ func TestOperation_Execute(t *testing.T) { { name: "operation fails but continues", operation: mock.MockOperation{ - ExecFn: func(ctx context.Context) error { + ExecFn: func(_ context.Context, _ binding.Bindings) error { return errors.New("operation failed") }, }, @@ -36,7 +37,7 @@ func TestOperation_Execute(t *testing.T) { { name: "operation fails and don't continues", operation: mock.MockOperation{ - ExecFn: func(ctx context.Context) error { + ExecFn: func(_ context.Context, _ binding.Bindings) error { return errors.New("operation failed") }, }, @@ -47,7 +48,7 @@ func TestOperation_Execute(t *testing.T) { { name: "operation succeeds", operation: mock.MockOperation{ - ExecFn: func(ctx context.Context) error { + ExecFn: func(_ context.Context, _ binding.Bindings) error { return nil }, }, diff --git a/pkg/runner/processors/step.go b/pkg/runner/processors/step.go index a5757afa8..5abd7a746 100644 --- a/pkg/runner/processors/step.go +++ b/pkg/runner/processors/step.go @@ -10,11 +10,9 @@ import ( "github.com/kyverno/chainsaw/pkg/apis/v1alpha1" "github.com/kyverno/chainsaw/pkg/client" "github.com/kyverno/chainsaw/pkg/discovery" - mutation "github.com/kyverno/chainsaw/pkg/mutate" "github.com/kyverno/chainsaw/pkg/report" "github.com/kyverno/chainsaw/pkg/resource" "github.com/kyverno/chainsaw/pkg/runner/cleanup" - "github.com/kyverno/chainsaw/pkg/runner/functions" "github.com/kyverno/chainsaw/pkg/runner/kubectl" "github.com/kyverno/chainsaw/pkg/runner/logging" "github.com/kyverno/chainsaw/pkg/runner/namespacer" @@ -30,7 +28,6 @@ import ( runnertemplate "github.com/kyverno/chainsaw/pkg/runner/template" "github.com/kyverno/chainsaw/pkg/runner/timeout" "github.com/kyverno/chainsaw/pkg/testing" - "github.com/kyverno/kyverno-json/pkg/engine/template" "github.com/kyverno/kyverno/ext/output/color" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/rest" @@ -88,15 +85,10 @@ type stepProcessor struct { func (p *stepProcessor) Run(ctx context.Context) { t := testing.FromContext(ctx) logger := logging.FromContext(ctx) - bindings := p.bindings - for _, b := range p.step.Bindings { - // TODO: check binding name is allowed ? - patched, err := mutation.Mutate(ctx, nil, mutation.Parse(ctx, b.Value.Value), nil, bindings, template.WithFunctionCaller(functions.Caller)) - if err != nil { - logging.Log(ctx, logging.Internal, logging.ErrorStatus, color.BoldRed, logging.ErrSection(err)) - t.FailNow() - } - bindings = bindings.Register("$"+b.Name, binding.NewBinding(patched)) + bindings, err := registerBindings(ctx, p.bindings, p.step.Bindings...) + if err != nil { + logging.Log(ctx, logging.Internal, logging.ErrorStatus, color.BoldRed, logging.ErrSection(err)) + t.FailNow() } try, err := p.tryOperations(ctx, bindings, p.step.TestStepSpec.Try...) if err != nil { @@ -181,11 +173,8 @@ func (p *stepProcessor) tryOperations(ctx context.Context, bindings binding.Bind } register(loaded...) } else if handler.Delete != nil { - loaded, err := p.deleteOperation(ctx, bindings, *handler.Delete) - if err != nil { - return nil, err - } - register(*loaded) + loaded := p.deleteOperation(ctx, bindings, *handler.Delete) + register(loaded) } else if handler.Error != nil { loaded, err := p.errorOperation(ctx, bindings, *handler.Error) if err != nil { @@ -249,11 +238,8 @@ func (p *stepProcessor) catchOperations(ctx context.Context, bindings binding.Bi } register(p.commandOperation(ctx, bindings, *cmd)) } else if handler.Delete != nil { - loaded, err := p.deleteOperation(ctx, bindings, *handler.Delete) - if err != nil { - return nil, err - } - register(*loaded) + loaded := p.deleteOperation(ctx, bindings, *handler.Delete) + register(loaded) } else if handler.Command != nil { register(p.commandOperation(ctx, bindings, *handler.Command)) } else if handler.Script != nil { @@ -307,11 +293,8 @@ func (p *stepProcessor) finallyOperations(ctx context.Context, bindings binding. } register(p.commandOperation(ctx, bindings, *cmd)) } else if handler.Delete != nil { - loaded, err := p.deleteOperation(ctx, bindings, *handler.Delete) - if err != nil { - return nil, err - } - register(*loaded) + loaded := p.deleteOperation(ctx, bindings, *handler.Delete) + register(loaded) } else if handler.Command != nil { register(p.commandOperation(ctx, bindings, *handler.Command)) } else if handler.Script != nil { @@ -343,10 +326,14 @@ func (p *stepProcessor) applyOperation(ctx context.Context, bindings binding.Bin if err := p.prepareResource(resource); err != nil { return nil, err } - ops = append(ops, operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.ApplyDuration()), - operation: opapply.New(cluster, resource, p.namespacer, p.getCleaner(ctx, dryRun), bindings, template, op.Expect), - }) + ops = append(ops, newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.ApplyDuration()), + opapply.New(cluster, resource, p.namespacer, p.getCleaner(ctx, dryRun), template, op.Expect), + nil, + bindings, + op.Bindings..., + )) } return ops, nil } @@ -365,11 +352,14 @@ func (p *stepProcessor) assertOperation(ctx context.Context, bindings binding.Bi _, cluster := p.clusters.client(op.Cluster, p.step.Cluster, p.test.Spec.Cluster) bindings = bindings.Register("$client", binding.NewBinding(cluster)) for _, resource := range resources { - ops = append(ops, operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.AssertDuration()), - operation: opassert.New(cluster, resource, p.namespacer, bindings, template), - operationReport: operationReport, - }) + ops = append(ops, newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.AssertDuration()), + opassert.New(cluster, resource, p.namespacer, template), + operationReport, + bindings, + op.Bindings..., + )) } return ops, nil } @@ -385,11 +375,13 @@ func (p *stepProcessor) commandOperation(ctx context.Context, bindings binding.B } config, cluster := p.clusters.client(op.Cluster, p.step.Cluster, p.test.Spec.Cluster) bindings = bindings.Register("$client", binding.NewBinding(cluster)) - return operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.ExecDuration()), - operation: opcommand.New(op, p.test.BasePath, ns, bindings, config), - operationReport: operationReport, - } + return newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.ExecDuration()), + opcommand.New(op, p.test.BasePath, ns, config), + operationReport, + bindings, + ) } func (p *stepProcessor) createOperation(ctx context.Context, bindings binding.Bindings, op v1alpha1.Create) ([]operation, error) { @@ -410,15 +402,19 @@ func (p *stepProcessor) createOperation(ctx context.Context, bindings binding.Bi if err := p.prepareResource(resource); err != nil { return nil, err } - ops = append(ops, operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.ApplyDuration()), - operation: opcreate.New(cluster, resource, p.namespacer, p.getCleaner(ctx, dryRun), bindings, template, op.Expect), - }) + ops = append(ops, newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.ApplyDuration()), + opcreate.New(cluster, resource, p.namespacer, p.getCleaner(ctx, dryRun), template, op.Expect), + nil, + bindings, + op.Bindings..., + )) } return ops, nil } -func (p *stepProcessor) deleteOperation(ctx context.Context, bindings binding.Bindings, op v1alpha1.Delete) (*operation, error) { +func (p *stepProcessor) deleteOperation(ctx context.Context, bindings binding.Bindings, op v1alpha1.Delete) operation { var resource unstructured.Unstructured resource.SetAPIVersion(op.APIVersion) resource.SetKind(op.Kind) @@ -432,11 +428,14 @@ func (p *stepProcessor) deleteOperation(ctx context.Context, bindings binding.Bi template := runnertemplate.Get(op.Template, p.step.Template, p.test.Spec.Template, p.config.Template) _, cluster := p.clusters.client(op.Cluster, p.step.Cluster, p.test.Spec.Cluster) bindings = bindings.Register("$client", binding.NewBinding(cluster)) - return &operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.DeleteDuration()), - operation: opdelete.New(cluster, resource, p.namespacer, bindings, template, op.Expect...), - operationReport: operationReport, - }, nil + return newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.DeleteDuration()), + opdelete.New(cluster, resource, p.namespacer, template, op.Expect...), + operationReport, + bindings, + op.Bindings..., + ) } func (p *stepProcessor) errorOperation(ctx context.Context, bindings binding.Bindings, op v1alpha1.Error) ([]operation, error) { @@ -453,11 +452,14 @@ func (p *stepProcessor) errorOperation(ctx context.Context, bindings binding.Bin _, cluster := p.clusters.client(op.Cluster, p.step.Cluster, p.test.Spec.Cluster) bindings = bindings.Register("$client", binding.NewBinding(cluster)) for _, resource := range resources { - ops = append(ops, operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.ErrorDuration()), - operation: operror.New(cluster, resource, p.namespacer, bindings, template), - operationReport: operationReport, - }) + ops = append(ops, newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.ErrorDuration()), + operror.New(cluster, resource, p.namespacer, template), + operationReport, + bindings, + op.Bindings..., + )) } return ops, nil } @@ -480,10 +482,14 @@ func (p *stepProcessor) patchOperation(ctx context.Context, bindings binding.Bin if err := p.prepareResource(resource); err != nil { return nil, err } - ops = append(ops, operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.ApplyDuration()), - operation: oppatch.New(cluster, resource, p.namespacer, bindings, template, op.Expect), - }) + ops = append(ops, newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.ApplyDuration()), + oppatch.New(cluster, resource, p.namespacer, template, op.Expect), + nil, + bindings, + op.Bindings..., + )) } return ops, nil } @@ -499,22 +505,27 @@ func (p *stepProcessor) scriptOperation(ctx context.Context, bindings binding.Bi } config, cluster := p.clusters.client(op.Cluster, p.step.Cluster, p.test.Spec.Cluster) bindings = bindings.Register("$client", binding.NewBinding(cluster)) - return operation{ - timeout: timeout.Get(op.Timeout, p.timeouts.ExecDuration()), - operation: opscript.New(op, p.test.BasePath, ns, bindings, config), - operationReport: operationReport, - } + return newOperation( + false, + timeout.Get(op.Timeout, p.timeouts.ExecDuration()), + opscript.New(op, p.test.BasePath, ns, config), + operationReport, + bindings, + ) } -func (p *stepProcessor) sleepOperation(ctx context.Context, bindings binding.Bindings, sleep v1alpha1.Sleep) operation { +func (p *stepProcessor) sleepOperation(ctx context.Context, bindings binding.Bindings, op v1alpha1.Sleep) operation { operationReport := report.NewOperation("Sleep ", report.OperationTypeSleep) if p.stepReport != nil { p.stepReport.AddOperation(operationReport) } - return operation{ - operation: opsleep.New(sleep), - operationReport: operationReport, - } + return newOperation( + false, + nil, + opsleep.New(op), + operationReport, + bindings, + ) } func (p *stepProcessor) fileRefOrCheck(ref v1alpha1.FileRefOrCheck) ([]unstructured.Unstructured, error) { diff --git a/pkg/runner/processors/test.go b/pkg/runner/processors/test.go index 77f0bd98b..993b5508b 100644 --- a/pkg/runner/processors/test.go +++ b/pkg/runner/processors/test.go @@ -9,10 +9,8 @@ import ( "github.com/kyverno/chainsaw/pkg/apis/v1alpha1" "github.com/kyverno/chainsaw/pkg/client" "github.com/kyverno/chainsaw/pkg/discovery" - mutation "github.com/kyverno/chainsaw/pkg/mutate" "github.com/kyverno/chainsaw/pkg/report" "github.com/kyverno/chainsaw/pkg/runner/cleanup" - "github.com/kyverno/chainsaw/pkg/runner/functions" "github.com/kyverno/chainsaw/pkg/runner/logging" "github.com/kyverno/chainsaw/pkg/runner/mutate" "github.com/kyverno/chainsaw/pkg/runner/namespacer" @@ -20,7 +18,6 @@ import ( "github.com/kyverno/chainsaw/pkg/runner/summary" "github.com/kyverno/chainsaw/pkg/runner/timeout" "github.com/kyverno/chainsaw/pkg/testing" - "github.com/kyverno/kyverno-json/pkg/engine/template" "github.com/kyverno/kyverno/ext/output/color" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -114,15 +111,10 @@ func (p *testProcessor) Run(ctx context.Context, nspacer namespacer.Namespacer) t.SkipNow() } } - bindings := p.bindings - for _, b := range p.test.Spec.Bindings { - // TODO: check binding name is allowed ? - patched, err := mutation.Mutate(ctx, nil, mutation.Parse(ctx, b.Value.Value), nil, bindings, template.WithFunctionCaller(functions.Caller)) - if err != nil { - logging.Log(ctx, logging.Internal, logging.ErrorStatus, color.BoldRed, logging.ErrSection(err)) - t.FailNow() - } - bindings = bindings.Register("$"+b.Name, binding.NewBinding(patched)) + bindings, err := registerBindings(ctx, p.bindings, p.test.Spec.Bindings...) + if err != nil { + logging.Log(ctx, logging.Internal, logging.ErrorStatus, color.BoldRed, logging.ErrSection(err)) + t.FailNow() } setupLogger := logging.NewLogger(t, p.clock, p.test.Name, fmt.Sprintf("%-*s", size, "@setup")) cleanupLogger := logging.NewLogger(t, p.clock, p.test.Name, fmt.Sprintf("%-*s", size, "@cleanup")) @@ -164,11 +156,13 @@ func (p *testProcessor) Run(ctx context.Context, nspacer namespacer.Namespacer) } if !cleanup.Skip(p.config.SkipDelete, p.test.Spec.SkipDelete, nil) { t.Cleanup(func() { - operation := operation{ - continueOnError: false, - timeout: timeout.Get(nil, p.timeouts.CleanupDuration()), - operation: opdelete.New(cluster, object, nspacer, bindings, false), - } + operation := newOperation( + false, + timeout.Get(nil, p.timeouts.CleanupDuration()), + opdelete.New(cluster, object, nspacer, false), + nil, + bindings, + ) operation.execute(cleanupCtx) }) } diff --git a/pkg/runner/processors/tests.go b/pkg/runner/processors/tests.go index 9217dfea0..5c26f7f8d 100644 --- a/pkg/runner/processors/tests.go +++ b/pkg/runner/processors/tests.go @@ -99,11 +99,13 @@ func (p *testsProcessor) Run(ctx context.Context) { } if !cleanup.Skip(p.config.SkipDelete, nil, nil) { t.Cleanup(func() { - operation := operation{ - continueOnError: false, - timeout: timeout.Get(nil, p.config.Timeouts.CleanupDuration()), - operation: opdelete.New(cluster, object, nspacer, bindings, false), - } + operation := newOperation( + false, + timeout.Get(nil, p.config.Timeouts.CleanupDuration()), + opdelete.New(cluster, object, nspacer, false), + nil, + bindings, + ) operation.execute(ctx) }) } diff --git a/testdata/e2e/examples/bindings/chainsaw-test.yaml b/testdata/e2e/examples/bindings/chainsaw-test.yaml index 6e2e13197..4585b7175 100644 --- a/testdata/e2e/examples/bindings/chainsaw-test.yaml +++ b/testdata/e2e/examples/bindings/chainsaw-test.yaml @@ -11,11 +11,12 @@ spec: - bindings: - name: b value: 2 - - name: c - value: ($a + $b) try: - - apply: + - apply: template: true + bindings: + - name: c + value: ($a + $b) resource: apiVersion: v1 kind: ConfigMap @@ -26,14 +27,15 @@ spec: - bindings: - name: b value: 2 - - name: c - value: ($a + $b) try: - assert: + bindings: + - name: c + value: ($a + $b) resource: apiVersion: v1 kind: ConfigMap metadata: name: quick-start data: - foo: '3' + foo: (to_string($c))