@@ -93,95 +93,49 @@ func (c *ControlPlaneContract) ControlPlaneEndpoint() *ControlPlaneEndpoint {
93
93
// NOTE: When working with unstructured there is no way to understand if the ControlPlane provider
94
94
// do support a field in the type definition from the fact that a field is not set in a given instance.
95
95
// This is why in we are deriving if replicas is required from the ClusterClass in the topology reconciler code.
96
- func (c * ControlPlaneContract ) Replicas () * Int64 {
97
- return & Int64 {
96
+ func (c * ControlPlaneContract ) Replicas () * Int32 {
97
+ return & Int32 {
98
98
path : []string {"spec" , "replicas" },
99
99
}
100
100
}
101
101
102
102
// StatusReplicas provide access to the status.replicas field in a ControlPlane object, if any. Applies to implementations using replicas.
103
- func (c * ControlPlaneContract ) StatusReplicas () * Int64 {
104
- return & Int64 {
103
+ func (c * ControlPlaneContract ) StatusReplicas () * Int32 {
104
+ return & Int32 {
105
105
path : []string {"status" , "replicas" },
106
106
}
107
107
}
108
108
109
- // UpdatedReplicas provide access to the status.updatedReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
110
- // TODO (v1beta2): Rename to V1Beta1DeprecatedUpdatedReplicas and make sure we are only using this method for compatibility with old contracts.
111
- func (c * ControlPlaneContract ) UpdatedReplicas (contractVersion string ) * Int64 {
112
- if contractVersion == "v1beta1" {
113
- return & Int64 {
114
- path : []string {"status" , "updatedReplicas" },
115
- }
116
- }
117
-
118
- return & Int64 {
119
- path : []string {"status" , "deprecated" , "v1beta1" , "updatedReplicas" },
120
- }
121
- }
122
-
123
109
// ReadyReplicas provide access to the status.readyReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
124
- // TODO (v1beta2): Rename to V1Beta1DeprecatedReadyReplicas and make sure we are only using this method for compatibility with old contracts.
125
- func (c * ControlPlaneContract ) ReadyReplicas (contractVersion string ) * Int64 {
126
- if contractVersion == "v1beta1" {
127
- return & Int64 {
128
- path : []string {"status" , "readyReplicas" },
129
- }
130
- }
131
-
132
- return & Int64 {
133
- path : []string {"status" , "deprecated" , "v1beta1" , "readyReplicas" },
134
- }
135
- }
136
-
137
- // UnavailableReplicas provide access to the status.unavailableReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
138
- // TODO (v1beta2): Rename to V1Beta1DeprecatedUnavailableReplicas and make sure we are only using this method for compatibility with old contracts.
139
- func (c * ControlPlaneContract ) UnavailableReplicas (contractVersion string ) * Int64 {
140
- if contractVersion == "v1beta1" {
141
- return & Int64 {
142
- path : []string {"status" , "unavailableReplicas" },
143
- }
144
- }
145
-
146
- return & Int64 {
147
- path : []string {"status" , "deprecated" , "v1beta1" , "unavailableReplicas" },
148
- }
149
- }
150
-
151
- // V1Beta2ReadyReplicas provide access to the status.readyReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
152
- // TODO (v1beta2): Drop V1Beta2 prefix..
153
- func (c * ControlPlaneContract ) V1Beta2ReadyReplicas (contractVersion string ) * Int32 {
154
- if contractVersion == "v1beta1" {
155
- return & Int32 {
156
- path : []string {"status" , "v1beta2" , "readyReplicas" },
157
- }
158
- }
159
-
110
+ // NOTE: readyReplicas changed semantic in v1beta2 contract.
111
+ func (c * ControlPlaneContract ) ReadyReplicas () * Int32 {
160
112
return & Int32 {
161
113
path : []string {"status" , "readyReplicas" },
162
114
}
163
115
}
164
116
165
- // V1Beta2AvailableReplicas provide access to the status.availableReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
166
- // TODO (v1beta2): Drop V1Beta2 prefix.x.
167
- func (c * ControlPlaneContract ) V1Beta2AvailableReplicas (contractVersion string ) * Int32 {
168
- if contractVersion == "v1beta1" {
169
- return & Int32 {
170
- path : []string {"status" , "v1beta2" , "availableReplicas" },
171
- }
172
- }
173
-
117
+ // AvailableReplicas provide access to the status.availableReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
118
+ // NOTE: availableReplicas was introduced by the v1beta2 contract; use unavailableReplicas for the v1beta1 contract.
119
+ func (c * ControlPlaneContract ) AvailableReplicas () * Int32 {
174
120
return & Int32 {
175
121
path : []string {"status" , "availableReplicas" },
176
122
}
177
123
}
178
124
179
- // V1Beta2UpToDateReplicas provide access to the status.upToDateReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
180
- // TODO (v1beta2): Drop V1Beta2 prefix.ix.
181
- func (c * ControlPlaneContract ) V1Beta2UpToDateReplicas (contractVersion string ) * Int32 {
125
+ // V1Beta1UnavailableReplicas provide access to the status.unavailableReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
126
+ // NOTE: use availableReplicas when working with the v1beta2 contract.
127
+ func (c * ControlPlaneContract ) V1Beta1UnavailableReplicas () * Int64 {
128
+ return & Int64 {
129
+ path : []string {"status" , "unavailableReplicas" },
130
+ }
131
+ }
132
+
133
+ // UpToDateReplicas provide access to the status.upToDateReplicas field in a ControlPlane object, if any. Applies to implementations using replicas.
134
+ // NOTE: upToDateReplicas was introduced by the v1beta2 contract; code will fall back to updatedReplicas for the v1beta1 contract.
135
+ func (c * ControlPlaneContract ) UpToDateReplicas (contractVersion string ) * Int32 {
182
136
if contractVersion == "v1beta1" {
183
137
return & Int32 {
184
- path : []string {"status" , "v1beta2" , "upToDateReplicas " },
138
+ path : []string {"status" , "updatedReplicas " },
185
139
}
186
140
}
187
141
@@ -291,13 +245,9 @@ func (c *ControlPlaneContract) IsUpgrading(obj *unstructured.Unstructured) (bool
291
245
func (c * ControlPlaneContract ) IsScaling (obj * unstructured.Unstructured , contractVersion string ) (bool , error ) {
292
246
desiredReplicas , err := c .Replicas ().Get (obj )
293
247
if err != nil {
294
- return false , errors .Wrap (err , "failed to get control plane spec replicas" )
248
+ return false , errors .Wrapf (err , "failed to get control plane %s" , c . Replicas (). Path (). String () )
295
249
}
296
250
297
- // TODO (v1beta2): Add a new code path using v1beta2 replica counters
298
- // note: currently we are still always using v1beta1 counters no matter if they are moved under deprecated
299
- // but we should stop doing this ASAP
300
-
301
251
statusReplicas , err := c .StatusReplicas ().Get (obj )
302
252
if err != nil {
303
253
if errors .Is (err , ErrFieldNotFound ) {
@@ -306,54 +256,68 @@ func (c *ControlPlaneContract) IsScaling(obj *unstructured.Unstructured, contrac
306
256
// so that we can block any operations that expect control plane to be stable.
307
257
return true , nil
308
258
}
309
- return false , errors .Wrap (err , "failed to get control plane status replicas" )
259
+ return false , errors .Wrapf (err , "failed to get control plane %s" , c . StatusReplicas (). Path (). String () )
310
260
}
311
261
312
- updatedReplicas , err := c .UpdatedReplicas (contractVersion ).Get (obj )
262
+ upToDatedReplicas , err := c .UpToDateReplicas (contractVersion ).Get (obj )
313
263
if err != nil {
314
264
if errors .Is (err , ErrFieldNotFound ) {
315
265
// If updatedReplicas is not set on the control plane
316
266
// we should consider the control plane to be scaling so that
317
267
// we block any operation that expect the control plane to be stable.
318
268
return true , nil
319
269
}
320
- return false , errors .Wrap (err , "failed to get control plane status updatedReplicas" )
270
+ return false , errors .Wrapf (err , "failed to get control plane %s" , c . UpToDateReplicas ( contractVersion ). Path (). String () )
321
271
}
322
272
323
- readyReplicas , err := c .ReadyReplicas (contractVersion ).Get (obj )
273
+ readyReplicas , err := c .ReadyReplicas ().Get (obj )
324
274
if err != nil {
325
275
if errors .Is (err , ErrFieldNotFound ) {
326
276
// If readyReplicas is not set on the control plane
327
277
// we should consider the control plane to be scaling so that
328
278
// we block any operation that expect the control plane to be stable.
329
279
return true , nil
330
280
}
331
- return false , errors .Wrap (err , "failed to get control plane status readyReplicas" )
281
+ return false , errors .Wrapf (err , "failed to get control plane %s" , c . ReadyReplicas (). Path (). String () )
332
282
}
333
283
334
- unavailableReplicas , err := c .UnavailableReplicas (contractVersion ).Get (obj )
335
- if err != nil {
336
- if ! errors .Is (err , ErrFieldNotFound ) {
337
- return false , errors .Wrap (err , "failed to get control plane status unavailableReplicas" )
284
+ var availableReplicas * int32
285
+ if contractVersion == "v1beta1" {
286
+ unavailableReplicas , err := c .V1Beta1UnavailableReplicas ().Get (obj )
287
+ if err != nil {
288
+ if ! errors .Is (err , ErrFieldNotFound ) {
289
+ return false , errors .Wrapf (err , "failed to get control plane %s" , c .V1Beta1UnavailableReplicas ().Path ().String ())
290
+ }
291
+ // If unavailableReplicas is not set on the control plane we assume it is 0.
292
+ // We have to do this as the following happens after clusterctl move with KCP:
293
+ // * clusterctl move creates the KCP object without status
294
+ // * the KCP controller won't patch the field to 0 if it doesn't exist
295
+ // * This is because the patchHelper marshals before/after object to JSON to calculate a diff
296
+ // and as the unavailableReplicas field is not a pointer, not set and 0 are both rendered as 0.
297
+ // If before/after of the field is the same (i.e. 0), there is no diff and thus also no patch to set it to 0.
298
+ unavailableReplicas = ptr.To [int64 ](0 )
299
+ }
300
+ availableReplicas = ptr .To (* desiredReplicas - int32 (* unavailableReplicas ))
301
+ } else {
302
+ availableReplicas , err = c .AvailableReplicas ().Get (obj )
303
+ if err != nil {
304
+ if errors .Is (err , ErrFieldNotFound ) {
305
+ // If readyReplicas is not set on the control plane
306
+ // we should consider the control plane to be scaling so that
307
+ // we block any operation that expect the control plane to be stable.
308
+ return true , nil
309
+ }
310
+ return false , errors .Wrapf (err , "failed to get control plane %s" , c .AvailableReplicas ().Path ().String ())
338
311
}
339
- // If unavailableReplicas is not set on the control plane we assume it is 0.
340
- // We have to do this as the following happens after clusterctl move with KCP:
341
- // * clusterctl move creates the KCP object without status
342
- // * the KCP controller won't patch the field to 0 if it doesn't exist
343
- // * This is because the patchHelper marshals before/after object to JSON to calculate a diff
344
- // and as the unavailableReplicas field is not a pointer, not set and 0 are both rendered as 0.
345
- // If before/after of the field is the same (i.e. 0), there is no diff and thus also no patch to set it to 0.
346
- unavailableReplicas = ptr.To [int64 ](0 )
347
312
}
348
313
349
314
// Control plane is still scaling if:
350
- // * .spec.replicas, .status.replicas, .status.updatedReplicas,
351
- // .status.readyReplicas are not equal and
352
- // * unavailableReplicas > 0
315
+ // * .spec.replicas, .status.replicas, .status.upToDateReplicas,
316
+ // .status.readyReplicas, .status.availableReplicas are not equal.
353
317
if * statusReplicas != * desiredReplicas ||
354
- * updatedReplicas != * desiredReplicas ||
318
+ * upToDatedReplicas != * desiredReplicas ||
355
319
* readyReplicas != * desiredReplicas ||
356
- * unavailableReplicas > 0 {
320
+ * availableReplicas != * desiredReplicas {
357
321
return true , nil
358
322
}
359
323
return false , nil
0 commit comments