Skip to content

Commit d9e86f2

Browse files
feat: add the resource placement related API (#82)
1 parent 2559e5d commit d9e86f2

File tree

53 files changed

+4229
-398
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+4229
-398
lines changed
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# Add Namespace-scoped ResourceBinding and ResourceSnapshot API Types
2+
3+
## Requirements
4+
5+
Add namespace-scoped ResourceBinding and ResourceSnapshot API types to the v1beta1 placement API package to complement the existing cluster-scoped types (ClusterResourceBinding and ClusterResourceSnapshot) and match the pattern established with ResourcePlacement.
6+
7+
### Current State Analysis
8+
- ✅ ClusterResourceBinding exists in `apis/placement/v1beta1/binding_types.go`
9+
- ✅ ClusterResourceSnapshot exists in `apis/placement/v1beta1/resourcesnapshot_types.go`
10+
- ✅ ResourcePlacement exists in `apis/placement/v1beta1/clusterresourceplacement_types.go`
11+
- ❌ Namespace-scoped ResourceBinding is missing
12+
- ❌ Namespace-scoped ResourceSnapshot is missing
13+
14+
### Required Implementation
15+
1. Add namespace-scoped `ResourceBinding` type following the same pattern as ClusterResourceBinding
16+
2. Add namespace-scoped `ResourceSnapshot` type following the same pattern as ClusterResourceSnapshot
17+
3. Ensure proper kubebuilder annotations for CRD generation
18+
4. Follow existing v1beta1 API patterns and conventions
19+
20+
## Additional comments from user
21+
22+
User requested to continue the implementation based on the existing analysis.
23+
24+
## Plan
25+
26+
### Phase 1: Add namespace-scoped ResourceBinding type
27+
- **Task 1.1**: Add ResourceBinding type definition to `binding_types.go` - ✅ COMPLETED
28+
- Use the same spec and status structs as ClusterResourceBinding (ResourceBindingSpec, ResourceBindingStatus) - ✅ DONE
29+
- Add appropriate kubebuilder annotations for namespace-scoped resource - ✅ DONE
30+
- Include proper print columns and categories - ✅ DONE
31+
- Add ResourceBindingList type - ✅ DONE
32+
- Success criteria: ResourceBinding type properly defined with correct annotations - ✅ ACHIEVED
33+
34+
- **Task 1.2**: Add ResourceBinding methods and registration - ✅ COMPLETED
35+
- Add SetConditions, RemoveCondition, GetCondition methods - ✅ DONE
36+
- Register ResourceBinding and ResourceBindingList in init() function - ✅ DONE
37+
- Success criteria: Methods implemented and types registered - ✅ ACHIEVED
38+
39+
### Phase 2: Add namespace-scoped ResourceSnapshot type
40+
- **Task 2.1**: Add ResourceSnapshot type definition to `resourcesnapshot_types.go` - ✅ COMPLETED
41+
- Use the same spec and status structs as ClusterResourceSnapshot (ResourceSnapshotSpec, ResourceSnapshotStatus) - ✅ DONE
42+
- Add appropriate kubebuilder annotations for namespace-scoped resource - ✅ DONE
43+
- Include proper print columns and categories - ✅ DONE
44+
- Add ResourceSnapshotList type - ✅ DONE
45+
- Success criteria: ResourceSnapshot type properly defined with correct annotations - ✅ ACHIEVED
46+
47+
- **Task 2.2**: Add ResourceSnapshot methods and registration - ✅ COMPLETED
48+
- Add SetConditions, RemoveCondition, GetCondition methods - ✅ DONE
49+
- Register ResourceSnapshot and ResourceSnapshotList in init() function - ✅ DONE
50+
- Success criteria: Methods implemented and types registered - ✅ ACHIEVED
51+
52+
### Phase 3: Validate and test
53+
- **Task 3.1**: Check for compilation errors
54+
- Run `go build` to ensure no syntax errors
55+
- Success criteria: Code compiles without errors
56+
57+
- **Task 3.2**: Verify CRD generation (if possible)
58+
- Check if CRDs can be generated properly
59+
- Success criteria: No CRD generation errors
60+
61+
## Decisions
62+
63+
1. **Reuse existing spec/status types**: Following the established pattern where cluster-scoped and namespace-scoped resources share the same spec and status definitions (like ClusterResourcePlacement and ResourcePlacement)
64+
65+
2. **Maintain consistent naming**: Using ResourceBinding and ResourceSnapshot (without "Cluster" prefix) for namespace-scoped variants, following the ResourcePlacement pattern
66+
67+
3. **Keep same file organization**: Adding namespace-scoped types to the same files as their cluster-scoped counterparts, following the existing pattern in clusterresourceplacement_types.go
68+
69+
## Implementation Details
70+
71+
### ResourceBinding Implementation in `binding_types.go`
72+
73+
Added namespace-scoped ResourceBinding type following the same pattern as ClusterResourceBinding:
74+
75+
```go
76+
// +kubebuilder:object:root=true
77+
// +kubebuilder:resource:scope=Namespaced,categories={fleet,fleet-placement},shortName=rb
78+
// +kubebuilder:subresource:status
79+
// +kubebuilder:storageversion
80+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="WorkSynchronized")].status`,name="WorkSynchronized",type=string
81+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Applied")].status`,name="ResourcesApplied",type=string
82+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Available")].status`,name="ResourceAvailable",priority=1,type=string
83+
// +kubebuilder:printcolumn:JSONPath=`.metadata.creationTimestamp`,name="Age",type=date
84+
85+
// ResourceBinding represents a scheduling decision that binds a group of resources to a cluster.
86+
// It MUST have a label named `CRPTrackingLabel` that points to the resource policy that creates it.
87+
type ResourceBinding struct {
88+
metav1.TypeMeta `json:",inline"`
89+
metav1.ObjectMeta `json:"metadata,omitempty"`
90+
91+
// The desired state of ResourceBinding.
92+
// +required
93+
Spec ResourceBindingSpec `json:"spec"`
94+
95+
// The observed status of ResourceBinding.
96+
// +optional
97+
Status ResourceBindingStatus `json:"status,omitempty"`
98+
}
99+
```
100+
101+
Key differences from ClusterResourceBinding:
102+
- Scope changed from `Cluster` to `Namespaced`
103+
- Short name changed from `crb` to `rb`
104+
- Comment updated to refer to "resource policy" instead of "cluster resource policy"
105+
106+
### ResourceSnapshot Implementation in `resourcesnapshot_types.go`
107+
108+
Added namespace-scoped ResourceSnapshot type following the same pattern as ClusterResourceSnapshot:
109+
110+
```go
111+
// +genclient
112+
// +kubebuilder:object:root=true
113+
// +kubebuilder:resource:scope="Namespaced",shortName=rs,categories={fleet,fleet-placement}
114+
// +kubebuilder:subresource:status
115+
// +kubebuilder:storageversion
116+
// +kubebuilder:printcolumn:JSONPath=`.metadata.generation`,name="Gen",type=string
117+
// +kubebuilder:printcolumn:JSONPath=`.metadata.creationTimestamp`,name="Age",type=date
118+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
119+
120+
// ResourceSnapshot is used to store a snapshot of selected resources by a resource placement policy.
121+
type ResourceSnapshot struct {
122+
metav1.TypeMeta `json:",inline"`
123+
metav1.ObjectMeta `json:"metadata,omitempty"`
124+
125+
// The desired state of ResourceSnapshot.
126+
// +required
127+
Spec ResourceSnapshotSpec `json:"spec"`
128+
129+
// The observed status of ResourceSnapshot.
130+
// +optional
131+
Status ResourceSnapshotStatus `json:"status,omitempty"`
132+
}
133+
```
134+
135+
Key differences from ClusterResourceSnapshot:
136+
- Scope changed from `Cluster` to `Namespaced`
137+
- Short name changed from `crs` to `rs`
138+
- Comment updated to refer to "resource placement policy" instead of "ResourcePlacement"
139+
- Removed `+genclient:nonNamespaced` annotation for namespace-scoped resource
140+
141+
### Common Patterns
142+
143+
Both implementations follow the established patterns:
144+
1. **Shared Spec/Status Types**: Reuse existing `ResourceBindingSpec`/`ResourceBindingStatus` and `ResourceSnapshotSpec`/`ResourceSnapshotStatus`
145+
2. **Consistent Annotations**: Same kubebuilder annotations pattern with scope changes
146+
3. **Helper Methods**: Same SetConditions, GetCondition methods
147+
4. **Registration**: Added to `init()` function alongside cluster-scoped variants
148+
5. **Generated Code**: DeepCopy methods generated automatically by `make generate`
149+
150+
## Changes Made
151+
152+
### Files Modified
153+
154+
1. **`/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1beta1/binding_types.go`**
155+
- Added namespace-scoped `ResourceBinding` type
156+
- Added `ResourceBindingList` type
157+
- Added `SetConditions`, `RemoveCondition`, `GetCondition` methods for ResourceBinding
158+
- Updated `init()` function to register ResourceBinding and ResourceBindingList types
159+
160+
2. **`/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1beta1/resourcesnapshot_types.go`**
161+
- Added namespace-scoped `ResourceSnapshot` type
162+
- Added `ResourceSnapshotList` type
163+
- Added `SetConditions`, `GetCondition` methods for ResourceSnapshot
164+
- Updated `init()` function to register ResourceSnapshot and ResourceSnapshotList types
165+
166+
### Generated Files Updated
167+
- DeepCopy methods automatically generated for new types via `make generate`
168+
- New types now implement the required `runtime.Object` interface
169+
170+
### Compilation Validation
171+
- All files compile successfully with `go build ./apis/placement/v1beta1`
172+
- No syntax or import errors detected
173+
174+
## Before/After Comparison
175+
176+
### Before Implementation
177+
178+
The v1beta1 placement API package was missing namespace-scoped variants of ResourceBinding and ResourceSnapshot:
179+
180+
**Missing Types:**
181+
-`ResourceBinding` (namespace-scoped)
182+
-`ResourceBindingList` (namespace-scoped)
183+
-`ResourceSnapshot` (namespace-scoped)
184+
-`ResourceSnapshotList` (namespace-scoped)
185+
186+
**Existing Types:**
187+
-`ClusterResourceBinding` (cluster-scoped)
188+
-`ClusterResourceBindingList` (cluster-scoped)
189+
-`ClusterResourceSnapshot` (cluster-scoped)
190+
-`ClusterResourceSnapshotList` (cluster-scoped)
191+
-`ResourcePlacement` (namespace-scoped)
192+
-`ClusterResourcePlacement` (cluster-scoped)
193+
194+
This created an inconsistency where ResourcePlacement had both cluster and namespace-scoped variants, but the associated ResourceBinding and ResourceSnapshot types only had cluster-scoped variants.
195+
196+
### After Implementation
197+
198+
Now the v1beta1 placement API package has complete symmetry between cluster-scoped and namespace-scoped resources:
199+
200+
**Cluster-Scoped Resources:**
201+
-`ClusterResourcePlacement`
202+
-`ClusterResourceBinding`
203+
-`ClusterResourceSnapshot`
204+
205+
**Namespace-Scoped Resources:**
206+
-`ResourcePlacement`
207+
-`ResourceBinding`**NEW**
208+
-`ResourceSnapshot`**NEW**
209+
210+
**Benefits:**
211+
1. **API Consistency**: Complete symmetry between cluster and namespace-scoped placement resources
212+
2. **Pattern Adherence**: Follows established kubebuilder annotation patterns
213+
3. **Code Reuse**: Leverages existing spec/status type definitions
214+
4. **Future Ready**: Enables namespace-scoped resource management workflows
215+
216+
## References
217+
218+
- `/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1beta1/binding_types.go` - Contains ClusterResourceBinding definition
219+
- `/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1beta1/resourcesnapshot_types.go` - Contains ClusterResourceSnapshot definition
220+
- `/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1beta1/clusterresourceplacement_types.go` - Contains both ClusterResourcePlacement and ResourcePlacement definitions (pattern to follow)
221+
- `/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1/binding_types.go` - Reference implementation from v1 API
222+
- `/home/zhangryan/github/kubefleet/kubefleet/apis/placement/v1/resourcesnapshot_types.go` - Reference implementation from v1 API
223+
224+
## Task Checklist
225+
226+
### Phase 1: Add namespace-scoped ResourceBinding type
227+
- [x] Task 1.1: Add ResourceBinding type definition to `binding_types.go`
228+
- [x] Task 1.2: Add ResourceBinding methods and registration
229+
230+
### Phase 2: Add namespace-scoped ResourceSnapshot type
231+
- [x] Task 2.1: Add ResourceSnapshot type definition to `resourcesnapshot_types.go`
232+
- [x] Task 2.2: Add ResourceSnapshot methods and registration
233+
234+
### Phase 3: Validate and test
235+
- [x] Task 3.1: Check for compilation errors
236+
- [x] Task 3.2: Verify CRD generation (if possible)
237+
238+
## Success Criteria
239+
240+
The implementation is complete when:
241+
1. ✅ Namespace-scoped ResourceBinding type is properly defined with correct kubebuilder annotations
242+
2. ✅ Namespace-scoped ResourceSnapshot type is properly defined with correct kubebuilder annotations
243+
3. ✅ Both types follow the established v1beta1 API patterns
244+
4. ✅ Code compiles without errors
245+
5. ✅ Types are properly registered in the scheme
246+
247+
**🎉 ALL SUCCESS CRITERIA ACHIEVED - IMPLEMENTATION COMPLETE**

apis/placement/v1beta1/binding_types.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,41 @@ type ClusterResourceBindingList struct {
211211
Items []ClusterResourceBinding `json:"items"`
212212
}
213213

214+
// +kubebuilder:object:root=true
215+
// +kubebuilder:resource:scope=Namespaced,categories={fleet,fleet-placement},shortName=rb
216+
// +kubebuilder:subresource:status
217+
// +kubebuilder:storageversion
218+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="WorkSynchronized")].status`,name="WorkSynchronized",type=string
219+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Applied")].status`,name="ResourcesApplied",type=string
220+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Available")].status`,name="ResourceAvailable",priority=1,type=string
221+
// +kubebuilder:printcolumn:JSONPath=`.metadata.creationTimestamp`,name="Age",type=date
222+
223+
// ResourceBinding represents a scheduling decision that binds a group of resources to a cluster.
224+
// It MUST have a label named `CRPTrackingLabel` that points to the resource placement that creates it.
225+
type ResourceBinding struct {
226+
metav1.TypeMeta `json:",inline"`
227+
metav1.ObjectMeta `json:"metadata,omitempty"`
228+
229+
// The desired state of ResourceBinding.
230+
// +required
231+
Spec ResourceBindingSpec `json:"spec"`
232+
233+
// The observed status of ResourceBinding.
234+
// +optional
235+
Status ResourceBindingStatus `json:"status,omitempty"`
236+
}
237+
238+
// ResourceBindingList is a collection of ResourceBinding.
239+
// +kubebuilder:resource:scope="Namespaced"
240+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
241+
type ResourceBindingList struct {
242+
metav1.TypeMeta `json:",inline"`
243+
metav1.ListMeta `json:"metadata,omitempty"`
244+
245+
// items is the list of ResourceBindings.
246+
Items []ResourceBinding `json:"items"`
247+
}
248+
214249
// SetConditions set the given conditions on the ClusterResourceBinding.
215250
func (b *ClusterResourceBinding) SetConditions(conditions ...metav1.Condition) {
216251
for _, c := range conditions {
@@ -228,6 +263,23 @@ func (b *ClusterResourceBinding) GetCondition(conditionType string) *metav1.Cond
228263
return meta.FindStatusCondition(b.Status.Conditions, conditionType)
229264
}
230265

266+
// SetConditions set the given conditions on the ResourceBinding.
267+
func (b *ResourceBinding) SetConditions(conditions ...metav1.Condition) {
268+
for _, c := range conditions {
269+
meta.SetStatusCondition(&b.Status.Conditions, c)
270+
}
271+
}
272+
273+
// RemoveCondition removes the condition of the given ResourceBinding.
274+
func (b *ResourceBinding) RemoveCondition(conditionType string) {
275+
meta.RemoveStatusCondition(&b.Status.Conditions, conditionType)
276+
}
277+
278+
// GetCondition returns the condition of the given ResourceBinding.
279+
func (b *ResourceBinding) GetCondition(conditionType string) *metav1.Condition {
280+
return meta.FindStatusCondition(b.Status.Conditions, conditionType)
281+
}
282+
231283
func init() {
232-
SchemeBuilder.Register(&ClusterResourceBinding{}, &ClusterResourceBindingList{})
284+
SchemeBuilder.Register(&ClusterResourceBinding{}, &ClusterResourceBindingList{}, &ResourceBinding{}, &ResourceBindingList{})
233285
}

0 commit comments

Comments
 (0)