Skip to content

Commit c9bf911

Browse files
committed
make sure the namespaced binding works
Signed-off-by: Ryan Zhang <[email protected]>
1 parent be3e0eb commit c9bf911

File tree

11 files changed

+338
-56
lines changed

11 files changed

+338
-56
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Refactor Work Name Generation - Common Base Name Format
2+
3+
## Requirements
4+
- Refactor `getWorkNamePrefixFromSnapshotName` function to use a common base name format for all work name generation
5+
- Use `namespace.name` format for namespaced placements and just `name` for cluster-scoped placements consistently
6+
- Remove redundant logic between cluster-scoped and namespaced placement handling
7+
- Fix existing bug where `namespace` variable is used instead of `resourceSnapshot.GetNamespace()`
8+
- Update tests to match the new unified format (tests currently expect `namespace-name` but should expect `namespace.name`)
9+
- Ensure all existing functionality continues to work
10+
11+
## Additional comments from user
12+
- The goal is to prevent naming conflicts between cluster-scoped and namespace-scoped placements
13+
- Want to use a unified approach for work name generation
14+
- Remove redundant logic and simplify the function
15+
16+
## Plan
17+
18+
### Phase 1: Analyze Current Implementation and Fix Existing Bug
19+
- [x] Review current implementation of `getWorkNamePrefixFromSnapshotName`
20+
- [x] Identify the bug where `namespace` is used instead of `resourceSnapshot.GetNamespace()`
21+
- [x] Review existing format constants in `commons.go`
22+
- [x] Review existing test cases to understand current expectations
23+
24+
### Phase 2: Fix Bug and Simplify Implementation
25+
- [ ] Task 2.1: Fix the existing bug where `namespace` variable is used incorrectly
26+
- [ ] Task 2.2: Simplify the function logic to remove redundant if/else blocks
27+
- [ ] Task 2.3: Use a common base name generation approach for both scenarios
28+
29+
### Phase 3: Update Tests
30+
- [ ] Task 3.1: Update test cases to expect the correct `namespace.name` format instead of `namespace-name`
31+
- [ ] Task 3.2: Add additional test cases to ensure comprehensive coverage
32+
- [ ] Task 3.3: Run tests to verify all changes work correctly
33+
34+
### Phase 4: Validation
35+
- [ ] Task 4.1: Run unit tests to ensure all functionality works
36+
- [ ] Task 4.2: Review all usages of the function to ensure no breaking changes
37+
- [ ] Task 4.3: Verify the change achieves the goal of preventing naming conflicts
38+
39+
## Success Criteria
40+
- `getWorkNamePrefixFromSnapshotName` function uses a unified approach for work name generation
41+
- All existing tests pass with updated expectations
42+
- No naming conflicts between cluster-scoped and namespaced placements
43+
- Code is cleaner and more maintainable
44+
- Bug with `namespace` variable is fixed
45+
46+
## Decisions
47+
- Use the existing format constants that already follow the `namespace.name` pattern
48+
- Keep the same basic logic flow but simplify the branching
49+
- Update tests to match the intended behavior rather than the current buggy behavior
50+
51+
## Implementation Details
52+
53+
### Current Issues Found
54+
1. Bug in line where `namespace` is used instead of `resourceSnapshot.GetNamespace()`
55+
2. Redundant if/else logic that can be simplified
56+
3. Tests expect `namespace-name` format but constants define `namespace.name` format
57+
4. Function has duplicate logic for handling subindex scenarios
58+
59+
### Proposed Changes
60+
1. Fix the namespace variable bug
61+
2. Simplify to use a common base name generation approach
62+
3. Update tests to expect correct format
63+
4. Remove redundant branching logic
64+
65+
## Changes Made
66+
- [ ] Fixed namespace variable bug in `getWorkNamePrefixFromSnapshotName`
67+
- [ ] Simplified function logic to use unified approach
68+
- [ ] Updated test cases to expect correct format
69+
- [ ] Verified all tests pass
70+
71+
## Before/After Comparison
72+
**Before**: Redundant logic with separate handling for cluster-scoped vs namespaced, bug with namespace variable
73+
**After**: Unified approach with common base name format, bug fixed, cleaner code
74+
75+
## References
76+
- `pkg/controllers/workgenerator/controller.go` - main function location
77+
- `apis/placement/v1beta1/commons.go` - format constants
78+
- `pkg/controllers/workgenerator/controller_test.go` - test cases
79+
- User requirement to use common base name format and prevent naming conflicts
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Fix fetchAllResourceSnapshots Binding Type Support
2+
3+
## Requirements
4+
Fix the `fetchAllResourceSnapshots` function in the workgenerator controller to:
5+
1. Properly handle both ClusterResourceBinding and ResourceBinding objects
6+
2. Fetch the correct type of ResourceSnapshot (ClusterResourceSnapshot vs ResourceSnapshot) based on the binding type
7+
3. Fix the placement key generation to include namespace information for namespaced bindings
8+
4. Replace the incorrect use of CRPTrackingLabel (which only contains the placement name) with proper placement key generation
9+
10+
## Additional comments from user
11+
- The current implementation hardcodes ClusterResourceSnapshot type for master snapshot
12+
- The FetchAllResourceSnapshots function is called with only the CRPTrackingLabel (placement name) instead of the full placement key (namespace/name for namespaced placements)
13+
- Need to determine the resource snapshot type based on the binding type
14+
15+
## Plan
16+
17+
### Phase 1: Analysis and Understanding
18+
- [x] Analyze current fetchAllResourceSnapshots implementation
19+
- [x] Understand BindingObj interface and concrete types (ClusterResourceBinding vs ResourceBinding)
20+
- [x] Understand ResourceSnapshot types (ClusterResourceSnapshot vs ResourceSnapshot)
21+
- [x] Understand placement key format and generation
22+
23+
### Phase 2: Fix Resource Snapshot Type Detection
24+
- [x] Add logic to determine resource snapshot type based on binding type
25+
- [x] Update master resource snapshot fetch to use correct type
26+
- [x] Ensure proper type checking and error handling
27+
28+
### Phase 3: Fix Placement Key Generation
29+
- [x] Replace CRPTrackingLabel usage with proper placement key generation
30+
- [x] Use GetObjectKeyFromObj to generate correct placement key format
31+
- [x] Update FetchAllResourceSnapshots call to use proper placement key
32+
33+
### Phase 4: Testing and Validation
34+
- [x] Test with ClusterResourceBinding objects
35+
- [x] Test with ResourceBinding objects
36+
- [x] Verify correct resource snapshot types are fetched
37+
- [x] Ensure compilation and runtime correctness
38+
- [x] Add test cases for namespaced work name generation
39+
- [x] Verify all tests pass
40+
41+
## Implementation Details
42+
43+
### Current Issues Identified:
44+
1. **Hard-coded ClusterResourceSnapshot**: Line 701 hardcoded `ClusterResourceSnapshot{}` regardless of binding type ✅ FIXED
45+
2. **Incorrect placement key**: Line 711 used `resourceBinding.GetLabels()[fleetv1beta1.CRPTrackingLabel]` which only contains the placement name, not the full placement key format (namespace/name) ✅ FIXED
46+
3. **Type mismatch**: ResourceBinding should work with ResourceSnapshot, not ClusterResourceSnapshot ✅ FIXED
47+
4. **Work name conflicts**: Cluster-scoped and namespace-scoped placements with same name would generate identical work names ✅ FIXED
48+
49+
### Solution Implemented:
50+
1. **Type detection**: Added logic to check `resourceBinding.GetNamespace()` to determine if binding is cluster-scoped or namespaced
51+
2. **Dynamic snapshot type**: Fetch ClusterResourceSnapshot for ClusterResourceBinding, ResourceSnapshot for ResourceBinding
52+
3. **Proper placement key**: Use `controller.GetObjectKeyFromObj(resourceBinding)` to generate correct placement key format
53+
4. **Namespace-aware work names**: Include namespace in work names for namespaced placements to prevent conflicts
54+
55+
### Changes Made in Detail:
56+
57+
#### fetchAllResourceSnapshots function:
58+
- Added type detection based on `resourceBinding.GetNamespace()`
59+
- For cluster-scoped bindings (empty namespace): fetch ClusterResourceSnapshot
60+
- For namespaced bindings: fetch ResourceSnapshot with proper namespace
61+
- Replaced `CRPTrackingLabel` usage with `GetObjectKeyFromObj()` for proper placement key generation
62+
63+
#### getWorkNamePrefixFromSnapshotName function:
64+
- Added namespace awareness for work name generation
65+
- For namespaced resource snapshots: work name becomes `{namespace}-{placementName}-work` or `{namespace}-{placementName}-{subindex}`
66+
- For cluster-scoped resource snapshots: work name remains `{placementName}-work` or `{placementName}-{subindex}`
67+
- Added comprehensive test cases for both scenarios
68+
69+
### Success Criteria:
70+
- [x] Function works correctly with both ClusterResourceBinding and ResourceBinding
71+
- [x] Correct resource snapshot types are fetched based on binding type
72+
- [x] Placement key includes namespace information for namespaced bindings
73+
- [x] Work names include namespace to prevent conflicts between cluster-scoped and namespaced placements
74+
- [x] All tests pass
75+
- [x] Code compiles without errors
76+
77+
## Changes Made
78+
79+
### Task 2.1: Add Resource Snapshot Type Detection
80+
- [x] Add logic to determine resource snapshot type based on binding type
81+
- [x] Update master resource snapshot fetching logic
82+
83+
### Task 2.2: Fix Placement Key Generation
84+
- [x] Replace CRPTrackingLabel usage with GetObjectKeyFromObj
85+
- [x] Update FetchAllResourceSnapshots call
86+
87+
### Task 2.3: Update Error Handling
88+
- [x] Add appropriate error handling for type detection
89+
- [x] Update logging messages
90+
91+
### Task 2.4: Fix Work Name Generation
92+
- [x] Update getWorkNamePrefixFromSnapshotName to include namespace for namespaced placements
93+
- [x] Prevent naming conflicts between cluster-scoped and namespace-scoped placements with same name
94+
95+
## References
96+
- BindingObj interface: `/apis/placement/v1beta1/binding_types.go`
97+
- Placement resolver utilities: `/pkg/utils/controller/placement_resolver.go`
98+
- Resource snapshot resolver: `/pkg/utils/controller/resource_snapshot_resolver.go`
99+
- FetchAllResourceSnapshots: `/pkg/utils/controller/controller.go`

apis/placement/v1beta1/commons.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ const (
7878
// The name of the first work is {crpName}-{subindex}.
7979
WorkNameWithSubindexFmt = "%s-%d"
8080

81+
// WorkNameBaseFmt is the format of the base name of the work. It's formatted as {namespace}.{placementName}.
82+
WorkNameBaseFmt = "%s.%s"
83+
8184
// WorkNameWithConfigEnvelopeFmt is the format of the name of a work generated with a config envelope.
8285
// The format is {workPrefix}-configMap-uuid.
8386
WorkNameWithConfigEnvelopeFmt = "%s-configmap-%s"
@@ -101,6 +104,9 @@ const (
101104
// ParentBindingLabel is the label applied to work that contains the name of the binding that generates the work.
102105
ParentBindingLabel = fleetPrefix + "parent-resource-binding"
103106

107+
// ParentNamespaceLabel is the label applied to work that contains the namespace of the binding that generates the work.
108+
ParentNamespaceLabel = fleetPrefix + "parent-placement-namespace"
109+
104110
// CRPGenerationAnnotation indicates the generation of the CRP from which an object is derived or last updated.
105111
CRPGenerationAnnotation = fleetPrefix + "CRP-generation"
106112

pkg/controllers/clusterresourceplacement/controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (r *Reconciler) handleUpdate(ctx context.Context, crp *fleetv1beta1.Cluster
220220
klog.ErrorS(err, "Failed to extract the resource index from the clusterResourceSnapshot", "clusterResourcePlacement", crpKObj, "clusterResourceSnapshot", latestResourceSnapshotKObj)
221221
return ctrl.Result{}, controller.NewUnexpectedBehaviorError(err)
222222
}
223-
selectedResourceIDs, err = controller.CollectResourceIdentifiersUsingMasterClusterResourceSnapshot(ctx, r.Client, crp.Name, latestResourceSnapshot, strconv.Itoa(latestResourceSnapshotIndex))
223+
selectedResourceIDs, err = controller.CollectResourceIdentifiersUsingMasterResourceSnapshot(ctx, r.Client, crp.Name, latestResourceSnapshot, strconv.Itoa(latestResourceSnapshotIndex))
224224
if err != nil {
225225
klog.ErrorS(err, "Failed to collect resource identifiers from the clusterResourceSnapshot", "clusterResourcePlacement", crpKObj, "clusterResourceSnapshot", latestResourceSnapshotKObj)
226226
return ctrl.Result{}, err
@@ -1149,7 +1149,7 @@ func (r *Reconciler) determineRolloutStateForCRPWithExternalRolloutStrategy(
11491149
crp.Status.SelectedResources = selectedResourceIDs
11501150
} else {
11511151
crp.Status.ObservedResourceIndex = observedResourceIndex
1152-
selectedResources, err := controller.CollectResourceIdentifiersFromClusterResourceSnapshot(ctx, r.Client, crp.Name, observedResourceIndex)
1152+
selectedResources, err := controller.CollectResourceIdentifiersFromResourceSnapshot(ctx, r.Client, crp.Name, observedResourceIndex)
11531153
if err != nil {
11541154
klog.ErrorS(err, "Failed to collect resource identifiers from clusterResourceSnapshot", "clusterResourcePlacement", klog.KObj(crp), "resourceSnapshotIndex", observedResourceIndex)
11551155
return false, err

0 commit comments

Comments
 (0)