diff --git a/cmd/diff/cmd_utils.go b/cmd/diff/cmd_utils.go index 153b121..7207c1a 100644 --- a/cmd/diff/cmd_utils.go +++ b/cmd/diff/cmd_utils.go @@ -18,6 +18,7 @@ package main import ( "context" + "sync" "time" "github.com/alecthomas/kong" @@ -26,10 +27,15 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" "github.com/crossplane/crossplane-runtime/v2/pkg/logging" - - "github.com/crossplane/crossplane/v2/cmd/crank/render" ) +// globalRenderMutex serializes all render operations globally across all diff processors. +// This prevents concurrent Docker container operations that can overwhelm the Docker daemon +// when processing multiple XRs with the same functions. See issue #59. +// +//nolint:gochecknoglobals // Required for global serialization across processors +var globalRenderMutex sync.Mutex + // CommonCmdFields contains common fields shared by both XR and Comp commands. type CommonCmdFields struct { // Configuration options @@ -101,6 +107,5 @@ func defaultProcessorOptions() []dp.ProcessorOption { return []dp.ProcessorOption{ dp.WithColorize(true), dp.WithCompact(false), - dp.WithRenderFunc(render.Render), } } diff --git a/cmd/diff/comp.go b/cmd/diff/comp.go index de236fd..d046e4c 100644 --- a/cmd/diff/comp.go +++ b/cmd/diff/comp.go @@ -95,6 +95,7 @@ func makeDefaultCompProc(c *CompCmd, ctx *AppContext, log logging.Logger) dp.Com dp.WithLogger(log), dp.WithColorize(!c.NoColor), // Override default if NoColor is set dp.WithCompact(c.Compact), // Override default if Compact is set + dp.WithRenderMutex(&globalRenderMutex), ) // Create XR processor first (peer processor) diff --git a/cmd/diff/diff_integration_test.go b/cmd/diff/diff_integration_test.go index e0fc2fc..2d1bd54 100644 --- a/cmd/diff/diff_integration_test.go +++ b/cmd/diff/diff_integration_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "os" "path/filepath" run "runtime" "strconv" @@ -153,26 +152,12 @@ func runIntegrationTest(t *testing.T, testType DiffTestType, tests map[string]In } // Set up the test files - tempDir := t.TempDir() - var testFiles []string // Handle any additional input files - for i, inputFile := range tt.inputFiles { - testFile := filepath.Join(tempDir, fmt.Sprintf("test_%d.yaml", i)) - - content, err := os.ReadFile(inputFile) - if err != nil { - t.Fatalf("failed to read input file: %v", err) - } - - err = os.WriteFile(testFile, content, 0o644) - if err != nil { - t.Fatalf("failed to write test file: %v", err) - } - - testFiles = append(testFiles, testFile) - } + // Note: NewCompositeLoader handles both individual files and directories, + // so we can pass paths directly without special handling + testFiles = append(testFiles, tt.inputFiles...) // Create a buffer to capture the output var stdout bytes.Buffer @@ -1302,6 +1287,25 @@ Summary: 1 added`, expectedError: false, noColor: true, }, + "Concurrent rendering with multiple functions and XRs from directory": { + // This test reproduces issue #59 - concurrent function startup failures + // when processing multiple XR files from a directory + inputFiles: []string{ + "testdata/diff/concurrent-xrs", // Pass the directory containing all XR files + }, + setupFiles: []string{ + "testdata/diff/resources/xrd-concurrent.yaml", + "testdata/diff/resources/composition-multi-functions.yaml", + "testdata/diff/resources/functions.yaml", + }, + // We expect successful processing of all 5 XRs + // Each XR should produce 3 base resources + 2 additional resources = 5 resources per XR + // Plus the XR itself = 6 additions per XR + // Total: 5 XRs * 6 additions = 30 additions + expectedOutput: "Summary: 30 added", + expectedError: false, + noColor: true, + }, } runIntegrationTest(t, XRDiffTest, tests) diff --git a/cmd/diff/diffprocessor/diff_processor.go b/cmd/diff/diffprocessor/diff_processor.go index 193c6bf..695a9a8 100644 --- a/cmd/diff/diffprocessor/diff_processor.go +++ b/cmd/diff/diffprocessor/diff_processor.go @@ -12,6 +12,7 @@ import ( k8 "github.com/crossplane-contrib/crossplane-diff/cmd/diff/client/kubernetes" "github.com/crossplane-contrib/crossplane-diff/cmd/diff/renderer" dt "github.com/crossplane-contrib/crossplane-diff/cmd/diff/renderer/types" + "github.com/crossplane-contrib/crossplane-diff/cmd/diff/serial" "github.com/crossplane-contrib/crossplane-diff/cmd/diff/types" un "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -70,6 +71,12 @@ func NewDiffProcessor(k8cs k8.Clients, xpcs xp.Clients, opts ...ProcessorOption) // Set default factory functions if not provided config.SetDefaultFactories() + // Wrap the RenderFunc with serialization if a mutex was provided + // This transparently handles serialization without requiring callers to worry about it + if config.RenderMutex != nil { + config.RenderFunc = serial.RenderFunc(config.RenderFunc, config.RenderMutex) + } + // Create the diff options based on configuration diffOpts := config.GetDiffOptions() @@ -210,6 +217,9 @@ func (p *DefaultDiffProcessor) DiffSingleResource(ctx context.Context, res *un.U return nil, errors.Wrap(err, "cannot get functions from pipeline") } + // Note: Serialization mutex prevents concurrent Docker operations. + // In e2e tests, named Docker containers (via annotations) reuse containers across renders. + // Apply XRD defaults before rendering err = p.applyXRDDefaults(ctx, xr, resourceID) if err != nil { diff --git a/cmd/diff/diffprocessor/processor_config.go b/cmd/diff/diffprocessor/processor_config.go index ce57c4d..ecdfc59 100644 --- a/cmd/diff/diffprocessor/processor_config.go +++ b/cmd/diff/diffprocessor/processor_config.go @@ -1,6 +1,8 @@ package diffprocessor import ( + "sync" + xp "github.com/crossplane-contrib/crossplane-diff/cmd/diff/client/crossplane" k8 "github.com/crossplane-contrib/crossplane-diff/cmd/diff/client/kubernetes" "github.com/crossplane-contrib/crossplane-diff/cmd/diff/renderer" @@ -25,6 +27,9 @@ type ProcessorConfig struct { // RenderFunc is the function to use for rendering resources RenderFunc RenderFunc + // RenderMutex is the mutex used to serialize render operations (for internal use) + RenderMutex *sync.Mutex + // Factories provide factory functions for creating components Factories ComponentFactories } @@ -85,6 +90,13 @@ func WithRenderFunc(renderFn RenderFunc) ProcessorOption { } } +// WithRenderMutex sets the mutex for serializing render operations. +func WithRenderMutex(mu *sync.Mutex) ProcessorOption { + return func(config *ProcessorConfig) { + config.RenderMutex = mu + } +} + // WithResourceManagerFactory sets the ResourceManager factory function. func WithResourceManagerFactory(factory func(k8.ResourceClient, xp.DefinitionClient, logging.Logger) ResourceManager) ProcessorOption { return func(config *ProcessorConfig) { diff --git a/cmd/diff/serial/serial.go b/cmd/diff/serial/serial.go new file mode 100644 index 0000000..b5088fd --- /dev/null +++ b/cmd/diff/serial/serial.go @@ -0,0 +1,73 @@ +/* +Copyright 2025 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package serial provides utilities for serializing render operations. +package serial + +import ( + "context" + "sync" + "time" + + "github.com/crossplane/crossplane-runtime/v2/pkg/logging" + + "github.com/crossplane/crossplane/v2/cmd/crank/render" +) + +// RenderFunc wraps a render function to serialize all render calls using the provided mutex. +// This prevents concurrent Docker container operations that can overwhelm the Docker daemon +// when processing many XRs with the same functions. The serialization ensures: +// +// 1. Only one render operation runs at a time globally +// 2. Named Docker containers (via annotations) can be reused safely between renders +// 3. Container startup races are eliminated +// +// For e2e tests, combine this with versioned named container annotations for optimal performance. +// For production, this works without requiring users to annotate their Function resources. +func RenderFunc( + renderFunc func(context.Context, logging.Logger, render.Inputs) (render.Outputs, error), + mu *sync.Mutex, +) func(context.Context, logging.Logger, render.Inputs) (render.Outputs, error) { + renderCount := 0 + + return func(ctx context.Context, log logging.Logger, in render.Inputs) (render.Outputs, error) { + mu.Lock() + defer mu.Unlock() + + renderCount++ + log.Debug("Starting serialized render", + "renderNumber", renderCount, + "functionCount", len(in.Functions)) + + start := time.Now() + result, err := renderFunc(ctx, log, in) + duration := time.Since(start) + + if err != nil { + log.Debug("Render completed with error", + "renderNumber", renderCount, + "error", err, + "duration", duration) + } else { + log.Debug("Render completed successfully", + "renderNumber", renderCount, + "duration", duration, + "composedResourceCount", len(result.ComposedResources)) + } + + return result, err + } +} diff --git a/cmd/diff/serial/serial_test.go b/cmd/diff/serial/serial_test.go new file mode 100644 index 0000000..8f1c57d --- /dev/null +++ b/cmd/diff/serial/serial_test.go @@ -0,0 +1,125 @@ +/* +Copyright 2025 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package serial + +import ( + "context" + "errors" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/crossplane/crossplane-runtime/v2/pkg/logging" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource/unstructured/composed" + + pkgv1 "github.com/crossplane/crossplane/v2/apis/pkg/v1" + "github.com/crossplane/crossplane/v2/cmd/crank/render" +) + +func TestRenderFunc_Passthrough(t *testing.T) { + type ctxKey string + key := ctxKey("test") + ctx := context.WithValue(t.Context(), key, "test-value") + inputs := render.Inputs{Functions: []pkgv1.Function{{}, {}}} + + var mu sync.Mutex + mockFunc := func(ctx context.Context, _ logging.Logger, in render.Inputs) (render.Outputs, error) { + // Verify context is passed through + if ctx.Value(key) != "test-value" { + t.Error("context not passed through") + } + // Verify inputs are passed through + if len(in.Functions) != 2 { + t.Errorf("expected 2 functions, got %d", len(in.Functions)) + } + return render.Outputs{ComposedResources: []composed.Unstructured{*composed.New(), *composed.New()}}, nil + } + + serialized := RenderFunc(mockFunc, &mu) + outputs, err := serialized(ctx, logging.NewNopLogger(), inputs) + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + // Verify outputs are returned + if len(outputs.ComposedResources) != 2 { + t.Errorf("expected 2 composed resources, got %d", len(outputs.ComposedResources)) + } +} + +func TestRenderFunc_Error(t *testing.T) { + var mu sync.Mutex + expectedErr := errors.New("render failed") + + mockFunc := func(_ context.Context, _ logging.Logger, _ render.Inputs) (render.Outputs, error) { + return render.Outputs{}, expectedErr + } + + serialized := RenderFunc(mockFunc, &mu) + _, err := serialized(t.Context(), logging.NewNopLogger(), render.Inputs{}) + + if !errors.Is(err, expectedErr) { + t.Errorf("expected error %v, got %v", expectedErr, err) + } +} + +func TestRenderFunc_Serialization(t *testing.T) { + var mu sync.Mutex + var concurrentCount atomic.Int32 + var maxConcurrent atomic.Int32 + + mockFunc := func(_ context.Context, _ logging.Logger, _ render.Inputs) (render.Outputs, error) { + current := concurrentCount.Add(1) + + // Update maxConcurrent if needed + for { + maxVal := maxConcurrent.Load() + if current <= maxVal || maxConcurrent.CompareAndSwap(maxVal, current) { + break + } + } + + time.Sleep(10 * time.Millisecond) + concurrentCount.Add(-1) + + return render.Outputs{}, nil + } + + serialized := RenderFunc(mockFunc, &mu) + + // Run multiple renders concurrently + const numCalls = 10 + var wg sync.WaitGroup + wg.Add(numCalls) + + for range numCalls { + go func() { + defer wg.Done() + if _, err := serialized(t.Context(), logging.NewNopLogger(), render.Inputs{}); err != nil { + t.Errorf("unexpected error: %v", err) + } + }() + } + + wg.Wait() + + // Verify that only one render ran at a time + if maxVal := maxConcurrent.Load(); maxVal != 1 { + t.Errorf("expected max concurrent executions to be 1, got %d", maxVal) + } +} diff --git a/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-1.yaml b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-1.yaml new file mode 100644 index 0000000..c5efc39 --- /dev/null +++ b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-1.yaml @@ -0,0 +1,8 @@ +apiVersion: concurrent.diff.example.org/v1alpha1 +kind: XConcurrentTest +metadata: + name: concurrent-test-1 + namespace: default +spec: + config: "test-config-1" + dataField: "data-1" \ No newline at end of file diff --git a/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-2.yaml b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-2.yaml new file mode 100644 index 0000000..c7cabbf --- /dev/null +++ b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-2.yaml @@ -0,0 +1,8 @@ +apiVersion: concurrent.diff.example.org/v1alpha1 +kind: XConcurrentTest +metadata: + name: concurrent-test-2 + namespace: default +spec: + config: "test-config-2" + dataField: "data-2" \ No newline at end of file diff --git a/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-3.yaml b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-3.yaml new file mode 100644 index 0000000..a09ea74 --- /dev/null +++ b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-3.yaml @@ -0,0 +1,8 @@ +apiVersion: concurrent.diff.example.org/v1alpha1 +kind: XConcurrentTest +metadata: + name: concurrent-test-3 + namespace: default +spec: + config: "test-config-3" + dataField: "data-3" \ No newline at end of file diff --git a/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-4.yaml b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-4.yaml new file mode 100644 index 0000000..6be5aaa --- /dev/null +++ b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-4.yaml @@ -0,0 +1,8 @@ +apiVersion: concurrent.diff.example.org/v1alpha1 +kind: XConcurrentTest +metadata: + name: concurrent-test-4 + namespace: default +spec: + config: "test-config-4" + dataField: "data-4" \ No newline at end of file diff --git a/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-5.yaml b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-5.yaml new file mode 100644 index 0000000..1a2669c --- /dev/null +++ b/cmd/diff/testdata/diff/concurrent-xrs/concurrent-xr-5.yaml @@ -0,0 +1,8 @@ +apiVersion: concurrent.diff.example.org/v1alpha1 +kind: XConcurrentTest +metadata: + name: concurrent-test-5 + namespace: default +spec: + config: "test-config-5" + dataField: "data-5" \ No newline at end of file diff --git a/cmd/diff/testdata/diff/crds/concurrent-additional-resource.yaml b/cmd/diff/testdata/diff/crds/concurrent-additional-resource.yaml new file mode 100644 index 0000000..82fcf07 --- /dev/null +++ b/cmd/diff/testdata/diff/crds/concurrent-additional-resource.yaml @@ -0,0 +1,34 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: xadditionalresources.concurrent.nop.example.org +spec: + group: concurrent.nop.example.org + names: + kind: XAdditionalResource + plural: xadditionalresources + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + forProvider: + properties: + index: + type: integer + config: + type: string + type: object + type: object + type: object + served: true + storage: true \ No newline at end of file diff --git a/cmd/diff/testdata/diff/crds/concurrent-base-resource.yaml b/cmd/diff/testdata/diff/crds/concurrent-base-resource.yaml new file mode 100644 index 0000000..9a0d7a8 --- /dev/null +++ b/cmd/diff/testdata/diff/crds/concurrent-base-resource.yaml @@ -0,0 +1,34 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: xbaseresources.concurrent.nop.example.org +spec: + group: concurrent.nop.example.org + names: + kind: XBaseResource + plural: xbaseresources + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + forProvider: + properties: + index: + type: integer + config: + type: string + type: object + type: object + type: object + served: true + storage: true \ No newline at end of file diff --git a/cmd/diff/testdata/diff/crds/xconcurrenttest-crd.yaml b/cmd/diff/testdata/diff/crds/xconcurrenttest-crd.yaml new file mode 100644 index 0000000..e9575f1 --- /dev/null +++ b/cmd/diff/testdata/diff/crds/xconcurrenttest-crd.yaml @@ -0,0 +1,75 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: xconcurrenttests.concurrent.diff.example.org +spec: + group: concurrent.diff.example.org + names: + kind: XConcurrentTest + listKind: XConcurrentTestList + plural: xconcurrenttests + singular: xconcurrenttest + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + config: + type: string + dataField: + type: string + crossplane: + type: object + properties: + compositionRef: + type: object + properties: + name: + type: string + compositionSelector: + type: object + properties: + matchLabels: + type: object + additionalProperties: + type: string + compositeDeletePolicy: + type: string + compositionUpdatePolicy: + type: string + resourceRefs: + type: array + items: + type: object + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + lastTransitionTime: + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string \ No newline at end of file diff --git a/cmd/diff/testdata/diff/resources/composition-multi-functions.yaml b/cmd/diff/testdata/diff/resources/composition-multi-functions.yaml new file mode 100644 index 0000000..ddda8d6 --- /dev/null +++ b/cmd/diff/testdata/diff/resources/composition-multi-functions.yaml @@ -0,0 +1,80 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: xconcurrenttests.diff.example.org +spec: + compositeTypeRef: + apiVersion: concurrent.diff.example.org/v1alpha1 + kind: XConcurrentTest + mode: Pipeline + pipeline: + # Step 1: Generate base resources + - step: generate-base-resources + functionRef: + name: function-go-templating + input: + apiVersion: template.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + {{- range $i := until 3 }} + --- + apiVersion: concurrent.nop.example.org/v1alpha1 + kind: XBaseResource + metadata: + name: {{ $.observed.composite.resource.metadata.name }}-base-{{ $i }} + namespace: {{ $.observed.composite.resource.metadata.namespace }} + annotations: + gotemplating.fn.crossplane.io/composition-resource-name: base-resource-{{ $i }} + spec: + forProvider: + index: {{ $i }} + config: {{ $.observed.composite.resource.spec.config }} + {{- end }} + + # Step 2: Apply environment configs + - step: apply-environment-configs + functionRef: + name: function-environment-configs + input: + apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 + kind: EnvironmentConfigs + + # Step 3: Generate additional resources + - step: generate-additional-resources + functionRef: + name: function-go-templating + input: + apiVersion: template.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + {{- range $i := until 2 }} + --- + apiVersion: concurrent.nop.example.org/v1alpha1 + kind: XAdditionalResource + metadata: + name: {{ $.observed.composite.resource.metadata.name }}-additional-{{ $i }} + namespace: {{ $.observed.composite.resource.metadata.namespace }} + annotations: + gotemplating.fn.crossplane.io/composition-resource-name: additional-resource-{{ $i }} + spec: + forProvider: + index: {{ $i }} + config: {{ $.observed.composite.resource.spec.config }} + {{- end }} + + # Step 4: Fetch extra resources if needed + - step: fetch-extra-resources + functionRef: + name: function-extra-resources + input: + apiVersion: extraresources.fn.crossplane.io/v1beta1 + kind: ExtraResources + + # Step 5: Auto-ready + - step: automatically-detect-ready-composed-resources + functionRef: + name: function-auto-ready \ No newline at end of file diff --git a/cmd/diff/testdata/diff/resources/xrd-concurrent.yaml b/cmd/diff/testdata/diff/resources/xrd-concurrent.yaml new file mode 100644 index 0000000..350d2c8 --- /dev/null +++ b/cmd/diff/testdata/diff/resources/xrd-concurrent.yaml @@ -0,0 +1,30 @@ +apiVersion: apiextensions.crossplane.io/v2 +kind: CompositeResourceDefinition +metadata: + name: xconcurrenttests.concurrent.diff.example.org +spec: + group: concurrent.diff.example.org + names: + kind: XConcurrentTest + plural: xconcurrenttests + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + config: + type: string + description: Configuration data for the test + default: "test-config" + dataField: + type: string + description: Additional data field + default: "default-data" + required: + - config \ No newline at end of file diff --git a/cmd/diff/xr.go b/cmd/diff/xr.go index 825bce2..9a1bea3 100644 --- a/cmd/diff/xr.go +++ b/cmd/diff/xr.go @@ -94,6 +94,7 @@ func makeDefaultXRProc(c *XRCmd, ctx *AppContext, log logging.Logger) dp.DiffPro dp.WithLogger(log), dp.WithColorize(!c.NoColor), // Override default if NoColor is set dp.WithCompact(c.Compact), // Override default if Compact is set + dp.WithRenderMutex(&globalRenderMutex), ) return dp.NewDiffProcessor(ctx.K8sClients, ctx.XpClients, opts...) diff --git a/go.mod b/go.mod index 2319855..3e5c6f6 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,10 @@ go 1.24.0 toolchain go1.25.2 -//replace github.com/crossplane/crossplane/v2 => /Users/jonathan.ogilvie/workspace/crossplane - require ( dario.cat/mergo v1.0.2 github.com/alecthomas/kong v1.12.1 - github.com/crossplane/crossplane-runtime/v2 v2.0.0 + github.com/crossplane/crossplane-runtime/v2 v2.1.0-rc.0 github.com/crossplane/crossplane/v2 v2.0.2 github.com/google/go-cmp v0.7.0 github.com/sergi/go-diff v1.4.0 diff --git a/go.sum b/go.sum index dc04ffa..5bbe877 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/crossplane/crossplane-runtime/v2 v2.0.0 h1:PK2pTKfshdDZ5IfoiMRiCi0PBnIjqbS0KGXEJgRdrb4= -github.com/crossplane/crossplane-runtime/v2 v2.0.0/go.mod h1:pkd5UzmE8esaZAApevMutR832GjJ1Qgc5Ngr78ByxrI= +github.com/crossplane/crossplane-runtime/v2 v2.1.0-rc.0 h1:T9KV7XKWCNVT7KAvUWPBGZVgO22YKvjDR9vWq1uyaFg= +github.com/crossplane/crossplane-runtime/v2 v2.1.0-rc.0/go.mod h1:pkd5UzmE8esaZAApevMutR832GjJ1Qgc5Ngr78ByxrI= github.com/crossplane/crossplane/v2 v2.0.2 h1:OKA26pnm3/uFHN1zF9d2CGkkvod9H/6PrK4xmL81BgU= github.com/crossplane/crossplane/v2 v2.0.2/go.mod h1:s0C2wok2nNwgrAozqBARzn02DfY1o1cNmPtUY7Dd/y8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/test/e2e/diff_test.go b/test/e2e/diff_test.go index 60031cb..48dcf16 100644 --- a/test/e2e/diff_test.go +++ b/test/e2e/diff_test.go @@ -743,3 +743,69 @@ func TestDiffExistingComposition(t *testing.T) { Feature(), ) } + +// TestDiffConcurrentDirectory tests issue #59 - concurrent function startup failures +// when processing multiple XR files from a directory with a composition using multiple functions. +func TestDiffConcurrentDirectory(t *testing.T) { + imageTag := strings.Split(environment.GetCrossplaneImage(), ":")[1] + manifests := filepath.Join("test/e2e/manifests/beta/diff", imageTag, "v2-concurrent-dir") + setupPath := filepath.Join(manifests, "setup") + xrsPath := filepath.Join(manifests, "xrs") + + environment.Test(t, + features.New("TestDiffConcurrentDirectory"). + WithLabel(e2e.LabelArea, LabelAreaDiff). + WithLabel(e2e.LabelSize, e2e.LabelSizeLarge). + WithLabel(config.LabelTestSuite, config.TestSuiteDefault). + WithLabel(LabelCrossplaneVersion, CrossplaneVersionMain). + WithSetup("CreatePrerequisites", funcs.AllOf( + funcs.ApplyResources(e2e.FieldManager, setupPath, "*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, setupPath, "*.yaml"), + )). + WithSetup("PrerequisitesAreReady", funcs.AllOf( + funcs.ResourcesHaveConditionWithin(1*time.Minute, setupPath, "definition.yaml", apiextensionsv1.WatchingComposite()), + funcs.ResourcesHaveConditionWithin(2*time.Minute, setupPath, "provider.yaml", pkgv1.Healthy(), pkgv1.Active()), + funcs.ResourcesHaveConditionWithin(3*time.Minute, setupPath, "functions.yaml", pkgv1.Healthy(), pkgv1.Active()), + )). + Assess("CanProcessDirectoryWithMultipleXRs", func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { + t.Helper() + + // Get all XR files from the directory + xrFiles, err := filepath.Glob(filepath.Join(xrsPath, "*.yaml")) + if err != nil { + t.Fatalf("Failed to find XR files: %v", err) + } + + if len(xrFiles) != 21 { + t.Fatalf("Expected 21 XR files, found %d", len(xrFiles)) + } + + // Run diff on all XR files - this tests concurrent function processing + output, log, err := RunXRDiff(t, c, "./crossplane-diff", xrFiles...) + + // Always log output for debugging + t.Logf("crossplane-diff stdout: %s", output) + t.Logf("crossplane-diff stderr: %s", log) + + if err != nil { + t.Fatalf("Error running diff command: %v", err) + } + + // Verify we processed all XRs - each XR creates 1 NopResource + // With 21 XRs, we should see 21 "+++ NopResource/" lines in the output + addedCount := strings.Count(output, "+++ NopResource/") + if addedCount != 21 { + t.Errorf("Expected 21 NopResource additions, found %d", addedCount) + } + + return ctx + }). + WithTeardown("DeletePrerequisites", funcs.AllOf( + funcs.DeleteResourcesWithPropagationPolicy(setupPath, "*.yaml", metav1.DeletePropagationForeground), + funcs.ResourcesDeletedWithin(3*time.Minute, setupPath, "*.yaml"), + )). + Feature(), + ) +} + +// end of file diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/composition.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/composition.yaml new file mode 100644 index 0000000..d33b88d --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/composition.yaml @@ -0,0 +1,64 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: xqueues.platform.example.com + labels: + provider: nop + service: test +spec: + compositeTypeRef: + apiVersion: platform.example.com/v1alpha1 + kind: XQueue + + mode: Pipeline + pipeline: + - step: create-queues + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + {{ $spec := .observed.composite.resource.spec }} + {{ $queueName := $spec.name }} + --- + apiVersion: nop.crossplane.io/v1alpha1 + kind: NopResource + metadata: + name: {{ lower $queueName }} + annotations: + crossplane.io/external-name: {{ $queueName }} + gotemplating.fn.crossplane.io/composition-resource-name: queue + spec: + forProvider: + conditionAfter: + - conditionType: Ready + conditionStatus: "True" + time: 0s + + - step: update-status + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + {{ $spec := .observed.composite.resource.spec }} + {{ if .observed.resources }} + {{ $mainQueue := index .observed.resources "queue" }} + {{ if $mainQueue }} + --- + apiVersion: platform.example.com/v1alpha1 + kind: XQueue + status: + ready: {{ $mainQueue.resource.status.conditions | len | gt 0 }} + {{ end }} + {{ end }} + + - step: automatically-detect-ready-composed-resources + functionRef: + name: function-auto-ready diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/definition.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/definition.yaml new file mode 100644 index 0000000..d67aee3 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/definition.yaml @@ -0,0 +1,79 @@ +apiVersion: apiextensions.crossplane.io/v2 +kind: CompositeResourceDefinition +metadata: + name: xqueues.platform.example.com +spec: + group: platform.example.com + names: + kind: XQueue + plural: xqueues + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + name: + type: string + description: "Name of the queue" + region: + type: string + description: "Region where the queue will be created" + mainQueue: + type: object + description: "Main queue configuration" + properties: + visibilityTimeoutSeconds: + type: number + default: 30 + messageRetentionSeconds: + type: number + default: 345600 + delaySeconds: + type: number + default: 0 + fifoQueue: + type: boolean + fifoThroughputLimit: + type: string + enum: ["perQueue", "perMessageGroupId"] + contentBasedDeduplication: + type: boolean + receiveWaitTimeSeconds: + type: number + default: 0 + maxMessageSize: + type: number + default: 262144 + kmsDataKeyReusePeriodSeconds: + type: number + default: 300 + sqsManagedSseEnabled: + type: boolean + extraTags: + type: object + additionalProperties: + type: string + description: "Additional tags to apply to the resources" + mode: + type: string + enum: ["manage", "observe", "noDelete", "noUpdate"] + description: "Resource management mode" + default: "manage" + required: + - name + - region + status: + type: object + properties: + queueArn: + type: string + description: "ARN of the created queue" + queueUrl: + type: string + description: "URL of the created queue" diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/functions.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/functions.yaml new file mode 100644 index 0000000..2ee5b88 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/functions.yaml @@ -0,0 +1,32 @@ +# Named Docker containers for performance optimization in concurrent processing tests. +# +# These annotations enable container reuse across multiple XR renders, providing significant +# performance benefits when processing many XRs with the same functions: +# - Without named containers: ~45 seconds for 21 XRs (creates new containers each time) +# - With named containers: ~6.7 seconds for 21 XRs (reuses containers after first creation) +# +# IMPORTANT: These annotations are ONLY used in this 21-file concurrent test where the +# performance benefit is substantial. Other e2e tests (single XR) don't include these +# annotations since they don't benefit meaningfully from container reuse. +# +# Production behavior: crossplane-diff uses mutex-only serialization without requiring +# users to annotate their Function resources, ensuring production compatibility while +# still preventing Docker daemon overload issues. +--- +apiVersion: pkg.crossplane.io/v1 +kind: Function +metadata: + name: function-go-templating + annotations: + render.crossplane.io/runtime-docker-name: "function-go-templating-v0.10.0" +spec: + package: xpkg.upbound.io/crossplane-contrib/function-go-templating:v0.10.0 +--- +apiVersion: pkg.crossplane.io/v1 +kind: Function +metadata: + name: function-auto-ready + annotations: + render.crossplane.io/runtime-docker-name: "function-auto-ready-v0.5.0" +spec: + package: xpkg.upbound.io/crossplane-contrib/function-auto-ready:v0.5.0 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/provider.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/provider.yaml new file mode 100644 index 0000000..5eb9690 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/setup/provider.yaml @@ -0,0 +1,7 @@ +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-nop +spec: + package: xpkg.upbound.io/crossplane-contrib/provider-nop:v0.5.0 + ignoreCrossplaneConstraints: true diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-01.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-01.yaml new file mode 100644 index 0000000..9b240ad --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-01.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-01 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-01 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-02.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-02.yaml new file mode 100644 index 0000000..f574a6a --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-02.yaml @@ -0,0 +1,19 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-02 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + maxMessageSize: 262144 + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-02 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-03.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-03.yaml new file mode 100644 index 0000000..4ea7fa0 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-03.yaml @@ -0,0 +1,19 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-03 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + fifoThroughputLimit: perQueue + contentBasedDeduplication: true + fifoQueue: true + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-03 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-04.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-04.yaml new file mode 100644 index 0000000..aada078 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-04.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-04 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-04 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-05.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-05.yaml new file mode 100644 index 0000000..59c9aa4 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-05.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-05 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-05 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-06.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-06.yaml new file mode 100644 index 0000000..bbe0261 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-06.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-06 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-06 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-07.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-07.yaml new file mode 100644 index 0000000..60caca6 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-07.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-07 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-07 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-08.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-08.yaml new file mode 100644 index 0000000..2dfe70f --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-08.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-08 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-08 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-09.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-09.yaml new file mode 100644 index 0000000..2e98adc --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-09.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-09 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-09 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-10.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-10.yaml new file mode 100644 index 0000000..2396aba --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-10.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-10 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-10 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-11.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-11.yaml new file mode 100644 index 0000000..2110918 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-11.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-11 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-11 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-12.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-12.yaml new file mode 100644 index 0000000..ec97eed --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-12.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-12 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-12 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-13.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-13.yaml new file mode 100644 index 0000000..bc6e73c --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-13.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-13 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-13 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-14.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-14.yaml new file mode 100644 index 0000000..65affe5 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-14.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-14 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-14 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-15.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-15.yaml new file mode 100644 index 0000000..11a8a26 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-15.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-15 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-15 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-16.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-16.yaml new file mode 100644 index 0000000..713ce39 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-16.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-16 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-16 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-17.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-17.yaml new file mode 100644 index 0000000..6d25f82 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-17.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-17 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-17 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-18.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-18.yaml new file mode 100644 index 0000000..b33e4c2 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-18.yaml @@ -0,0 +1,20 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-18 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + fifoThroughputLimit: perQueue + kmsDataKeyReusePeriodSeconds: 300 + contentBasedDeduplication: true + fifoQueue: true + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-18 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-19.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-19.yaml new file mode 100644 index 0000000..0ddbc5a --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-19.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-19 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-19 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-20.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-20.yaml new file mode 100644 index 0000000..05d02e9 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-20.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-20 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-20 + region: us-west-2 diff --git a/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-21.yaml b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-21.yaml new file mode 100644 index 0000000..43cf6e4 --- /dev/null +++ b/test/e2e/manifests/beta/diff/main/v2-concurrent-dir/xrs/queue-21.yaml @@ -0,0 +1,18 @@ +apiVersion: platform.example.com/v1alpha1 +kind: XQueue +metadata: + name: queue-21 + namespace: test-env +spec: + extraTags: + Deployment: test-env + mainQueue: + contentBasedDeduplication: false + fifoQueue: false + messageRetentionSeconds: 345600 + receiveWaitTimeSeconds: 15 + sqsManagedSseEnabled: false + visibilityTimeoutSeconds: 30 + mode: manage + name: test-queue-21 + region: us-west-2