Skip to content

Commit 4ae6822

Browse files
committed
fix: revert to earlier interface
Signed-off-by: Jonathan Ogilvie <[email protected]>
1 parent 3465321 commit 4ae6822

File tree

7 files changed

+42
-48
lines changed

7 files changed

+42
-48
lines changed

CLAUDE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ cmd/diff/
171171
- Compares rendered resources against cluster state via server-side dry-run
172172
- Detects additions, modifications, and removals
173173
- Handles `generateName` by matching via labels/annotations (`crossplane.io/composition-resource-name`)
174+
- Uses two-phase approach to correctly handle nested XRs:
175+
1. **Phase 1 - Non-removal diffs**: `CalculateNonRemovalDiffs` computes diffs for all rendered resources
176+
2. **Phase 2 - Removal detection**: `CalculateRemovedResourceDiffs` identifies resources to be removed
177+
- This separation is critical because nested XRs must be processed before detecting removals
178+
- Nested XRs may render additional composed resources that shouldn't be marked as removals
179+
180+
**Resource Management**
181+
- `ResourceManager` handles all resource fetching and cluster state operations
182+
- Key responsibilities:
183+
- `FetchCurrentObject`: Retrieves existing resource from cluster (for identity preservation)
184+
- `FetchObservedResources`: Fetches resource tree to find all composed resources (including nested)
185+
- `UpdateOwnerReferences`: Updates owner references with dry-run annotations
186+
- Separation of concerns: `DiffCalculator` focuses on diff logic, `ResourceManager` handles cluster I/O
187+
- Identity preservation: Fetches existing nested XRs to maintain their cluster identity across renders
174188

175189
## Design Principles
176190

cmd/diff/diffprocessor/diff_calculator.go

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ type DiffCalculator interface {
3333
// Returns: (diffs map, rendered resource keys, error)
3434
CalculateNonRemovalDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.Outputs) (map[string]*dt.ResourceDiff, map[string]bool, error)
3535

36-
// DetectRemovedResources identifies resources that exist in the cluster but are not
36+
// CalculateRemovedResourceDiffs identifies resources that exist in the cluster but are not
3737
// in the rendered set. This is called after nested XR processing is complete.
38-
DetectRemovedResources(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error)
38+
CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error)
3939
}
4040

4141
// DefaultDiffCalculator implements the DiffCalculator interface.
@@ -231,23 +231,6 @@ func (c *DefaultDiffCalculator) CalculateNonRemovalDiffs(ctx context.Context, xr
231231
return diffs, renderedResources, nil
232232
}
233233

234-
// DetectRemovedResources identifies resources that exist in the cluster but are not in the rendered set.
235-
// This should be called after all nested XRs have been processed to avoid false positives.
236-
func (c *DefaultDiffCalculator) DetectRemovedResources(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error) {
237-
xrName := xr.GetName()
238-
c.logger.Debug("Finding resources to be removed", "xr", xrName, "renderedCount", len(renderedResources))
239-
240-
removedDiffs, err := c.CalculateRemovedResourceDiffs(ctx, xr, renderedResources)
241-
if err != nil {
242-
c.logger.Debug("Error calculating removed resources", "error", err)
243-
return nil, err
244-
}
245-
246-
c.logger.Debug("Removal detection complete", "removedCount", len(removedDiffs), "xr", xrName)
247-
248-
return removedDiffs, nil
249-
}
250-
251234
// CalculateDiffs computes all diffs including removals for the rendered resources.
252235
// This is the primary method that most code should use.
253236
func (c *DefaultDiffCalculator) CalculateDiffs(ctx context.Context, xr *cmp.Unstructured, desired render.Outputs) (map[string]*dt.ResourceDiff, error) {
@@ -258,7 +241,7 @@ func (c *DefaultDiffCalculator) CalculateDiffs(ctx context.Context, xr *cmp.Unst
258241
}
259242

260243
// Then detect removed resources
261-
removedDiffs, err := c.DetectRemovedResources(ctx, xr.GetUnstructured(), renderedResources)
244+
removedDiffs, err := c.CalculateRemovedResourceDiffs(ctx, xr.GetUnstructured(), renderedResources)
262245
if err != nil {
263246
return nil, err
264247
}

cmd/diff/diffprocessor/diff_calculator_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ func TestDefaultDiffCalculator_CalculateDiffs(t *testing.T) {
731731
}
732732
}
733733

734-
func TestDefaultDiffCalculator_DetectRemovedResources(t *testing.T) {
734+
func TestDefaultDiffCalculator_CalculateRemovedResourceDiffs(t *testing.T) {
735735
ctx := t.Context()
736736

737737
// Create a test XR
@@ -844,16 +844,16 @@ func TestDefaultDiffCalculator_DetectRemovedResources(t *testing.T) {
844844
// Setup mocks
845845
applyClient, resourceTreeClient, resourceManager := tt.setupMocks(t)
846846

847-
// Create a diff calculator with the mocks (concrete type for testing internal method)
848-
calculator := &DefaultDiffCalculator{
849-
applyClient: applyClient,
850-
treeClient: resourceTreeClient,
851-
resourceManager: resourceManager,
852-
logger: logger,
853-
diffOptions: renderer.DefaultDiffOptions(),
854-
}
847+
// Create a diff calculator with the mocks
848+
calculator := NewDiffCalculator(
849+
applyClient,
850+
resourceTreeClient,
851+
resourceManager,
852+
logger,
853+
renderer.DefaultDiffOptions(),
854+
)
855855

856-
// Call the internal method under test
856+
// Call the method under test
857857
diffs, err := calculator.CalculateRemovedResourceDiffs(ctx, xr, tt.renderedResources)
858858

859859
if tt.wantErr {

cmd/diff/diffprocessor/diff_processor.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ func (p *DefaultDiffProcessor) diffSingleResourceInternal(ctx context.Context, r
339339
// which is only available on the existing cluster XR, not the modified XR from the input file.
340340
var existingXR *cmp.Unstructured
341341

342-
xrDiffKey := fmt.Sprintf("%s/%s/%s", xr.GetAPIVersion(), xr.GetKind(), xr.GetName())
342+
xrDiffKey := dt.MakeDiffKey(xr.GetAPIVersion(), xr.GetKind(), xr.GetName())
343343
if xrDiff, ok := diffs[xrDiffKey]; ok && xrDiff.Current != nil {
344344
// Convert from unstructured.Unstructured to composite.Unstructured
345345
existingXR = cmp.New()
@@ -380,7 +380,7 @@ func (p *DefaultDiffProcessor) diffSingleResourceInternal(ctx context.Context, r
380380
if detectRemovals && existingXR != nil {
381381
p.config.Logger.Debug("Detecting removed resources", "resource", resourceID, "renderedCount", len(renderedResources))
382382

383-
removedDiffs, err := p.diffCalculator.DetectRemovedResources(ctx, existingXR.GetUnstructured(), renderedResources)
383+
removedDiffs, err := p.diffCalculator.CalculateRemovedResourceDiffs(ctx, existingXR.GetUnstructured(), renderedResources)
384384
if err != nil {
385385
p.config.Logger.Debug("Error detecting removed resources (continuing)", "resource", resourceID, "error", err)
386386
} else if len(removedDiffs) > 0 {
@@ -398,9 +398,6 @@ func (p *DefaultDiffProcessor) diffSingleResourceInternal(ctx context.Context, r
398398
return diffs, renderedResources, err
399399
}
400400

401-
// ProcessNestedXRs recursively processes composed resources that are themselves XRs.
402-
// It checks each composed resource to see if it's an XR, and if so, processes it through
403-
// its own composition pipeline to get the full tree of diffs.
404401
// findExistingNestedXR locates an existing nested XR in the observed resources by matching
405402
// the composition-resource-name annotation and kind.
406403
func findExistingNestedXR(nestedXR *un.Unstructured, observedResources []cpd.Unstructured) *un.Unstructured {

cmd/diff/diffprocessor/diff_processor_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,8 +1796,8 @@ func TestDefaultDiffProcessor_ProcessNestedXRs(t *testing.T) {
17961796
},
17971797
parentResourceID: "XParentResource/parent-xr-abc",
17981798
depth: 1,
1799-
// TODO: This will currently fail because the nested XR gets "(generated)" name
1800-
// After fix, should NOT show managed resources as removed/added
1799+
// With identity preservation fix, nested XR maintains its cluster identity
1800+
// so managed resources show as modified rather than removed/added
18011801
wantDiffCount: 1, // Just the nested XR diff, not its managed resources as separate remove/add
18021802
wantErr: false,
18031803
},

cmd/diff/diffprocessor/requirements_provider.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package diffprocessor
22

33
import (
44
"context"
5-
"fmt"
65
"strings"
76
"sync"
87

98
xp "github.com/crossplane-contrib/crossplane-diff/cmd/diff/client/crossplane"
109
k8 "github.com/crossplane-contrib/crossplane-diff/cmd/diff/client/kubernetes"
10+
dt "github.com/crossplane-contrib/crossplane-diff/cmd/diff/renderer/types"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1212
un "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1313
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -76,7 +76,7 @@ func (p *RequirementsProvider) cacheResources(resources []*un.Unstructured) {
7676
defer p.cacheMutex.Unlock()
7777

7878
for _, res := range resources {
79-
key := fmt.Sprintf("%s/%s/%s", res.GetAPIVersion(), res.GetKind(), res.GetName())
79+
key := dt.MakeDiffKey(res.GetAPIVersion(), res.GetKind(), res.GetName())
8080
p.resourceCache[key] = res
8181
}
8282
}
@@ -86,7 +86,7 @@ func (p *RequirementsProvider) getCachedResource(apiVersion, kind, name string)
8686
p.cacheMutex.RLock()
8787
defer p.cacheMutex.RUnlock()
8888

89-
key := fmt.Sprintf("%s/%s/%s", apiVersion, kind, name)
89+
key := dt.MakeDiffKey(apiVersion, kind, name)
9090

9191
return p.resourceCache[key]
9292
}

cmd/diff/testutils/mocks.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -746,10 +746,10 @@ func (m *MockResourceTreeClient) GetResourceTree(ctx context.Context, root *un.U
746746

747747
// MockDiffCalculator is a mock implementation of DiffCalculator for testing.
748748
type MockDiffCalculator struct {
749-
CalculateDiffFn func(context.Context, *un.Unstructured, *un.Unstructured) (*dt.ResourceDiff, error)
750-
CalculateDiffsFn func(context.Context, *cmp.Unstructured, render.Outputs) (map[string]*dt.ResourceDiff, error)
751-
CalculateNonRemovalDiffsFn func(context.Context, *cmp.Unstructured, render.Outputs) (map[string]*dt.ResourceDiff, map[string]bool, error)
752-
DetectRemovedResourcesFn func(context.Context, *un.Unstructured, map[string]bool) (map[string]*dt.ResourceDiff, error)
749+
CalculateDiffFn func(context.Context, *un.Unstructured, *un.Unstructured) (*dt.ResourceDiff, error)
750+
CalculateDiffsFn func(context.Context, *cmp.Unstructured, render.Outputs) (map[string]*dt.ResourceDiff, error)
751+
CalculateNonRemovalDiffsFn func(context.Context, *cmp.Unstructured, render.Outputs) (map[string]*dt.ResourceDiff, map[string]bool, error)
752+
CalculateRemovedResourceDiffsFn func(context.Context, *un.Unstructured, map[string]bool) (map[string]*dt.ResourceDiff, error)
753753
}
754754

755755
// CalculateDiff implements DiffCalculator.
@@ -779,10 +779,10 @@ func (m *MockDiffCalculator) CalculateNonRemovalDiffs(ctx context.Context, xr *c
779779
return nil, nil, nil
780780
}
781781

782-
// DetectRemovedResources implements DiffCalculator.
783-
func (m *MockDiffCalculator) DetectRemovedResources(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error) {
784-
if m.DetectRemovedResourcesFn != nil {
785-
return m.DetectRemovedResourcesFn(ctx, xr, renderedResources)
782+
// CalculateRemovedResourceDiffs implements DiffCalculator.
783+
func (m *MockDiffCalculator) CalculateRemovedResourceDiffs(ctx context.Context, xr *un.Unstructured, renderedResources map[string]bool) (map[string]*dt.ResourceDiff, error) {
784+
if m.CalculateRemovedResourceDiffsFn != nil {
785+
return m.CalculateRemovedResourceDiffsFn(ctx, xr, renderedResources)
786786
}
787787

788788
return nil, nil

0 commit comments

Comments
 (0)