Skip to content

Commit 1d67e4b

Browse files
authored
chore: support the available condition with role (#9500)
1 parent e3c72bb commit 1d67e4b

9 files changed

Lines changed: 145 additions & 16 deletions

File tree

apis/apps/v1/componentdefinition_types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,13 @@ type ComponentAvailable struct {
12431243
// +optional
12441244
WithPhases *string `json:"withPhases,omitempty"`
12451245

1246+
// Specifies the role that the component will go through to be considered available.
1247+
//
1248+
// This field is immutable once set.
1249+
//
1250+
// +optional
1251+
WithRole *string `json:"withRole,omitempty"`
1252+
12461253
// Specifies the strategies for determining whether the component is available based on the available probe.
12471254
//
12481255
// This field is immutable once set.

apis/apps/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4214,6 +4214,13 @@ spec:
42144214
format: int32
42154215
type: integer
42164216
type: object
4217+
withRole:
4218+
description: |-
4219+
Specifies the role that the component will go through to be considered available.
4220+
4221+
4222+
This field is immutable once set.
4223+
type: string
42174224
type: object
42184225
configs:
42194226
description: |-

controllers/apps/component/transformer_component_status.go

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -344,23 +344,36 @@ func (t *componentStatusTransformer) reconcileStatusCondition(transCtx *componen
344344

345345
func (t *componentStatusTransformer) reconcileAvailableCondition(transCtx *componentTransformContext) error {
346346
policy := component.GetComponentAvailablePolicy(transCtx.CompDef)
347-
if policy.WithPhases == nil {
347+
if policy.WithPhases == nil && policy.WithRole == nil {
348348
return nil
349349
}
350350

351351
var (
352-
comp = transCtx.Component
352+
comp = transCtx.Component
353+
status, status1, status2 metav1.ConditionStatus
354+
reason, reason1, reason2 string
355+
message, message1, message2 string
353356
)
354-
status, reason, message := func() (metav1.ConditionStatus, string, string) {
355-
if comp.Status.Phase == "" {
356-
return metav1.ConditionUnknown, "Unknown", "the component phase is unknown"
357-
}
358-
phases := sets.New[string](strings.Split(strings.ToLower(*policy.WithPhases), ",")...)
359-
if phases.Has(strings.ToLower(string(comp.Status.Phase))) {
360-
return metav1.ConditionTrue, "Available", fmt.Sprintf("the component phase is %s", comp.Status.Phase)
357+
if policy.WithPhases != nil {
358+
status1, reason1, message1 = t.availableWithPhases(transCtx, comp, policy)
359+
}
360+
if policy.WithRole != nil {
361+
status2, reason2, message2 = t.availableWithRole(transCtx, comp, policy)
362+
}
363+
364+
// merge conditions
365+
switch {
366+
case policy.WithPhases != nil && policy.WithRole == nil:
367+
status, reason, message = status1, reason1, message1
368+
case policy.WithPhases == nil && policy.WithRole != nil:
369+
status, reason, message = status2, reason2, message2
370+
default: // both are not nil
371+
if status1 != metav1.ConditionTrue {
372+
status, reason, message = status1, reason1, message1
373+
} else {
374+
status, reason, message = status2, reason2, message2
361375
}
362-
return metav1.ConditionFalse, "Unavailable", fmt.Sprintf("the component phase is %s", comp.Status.Phase)
363-
}()
376+
}
364377

365378
cond := metav1.Condition{
366379
Type: appsv1.ConditionTypeAvailable,
@@ -373,10 +386,40 @@ func (t *componentStatusTransformer) reconcileAvailableCondition(transCtx *compo
373386
if meta.SetStatusCondition(&comp.Status.Conditions, cond) {
374387
transCtx.EventRecorder.Event(comp, corev1.EventTypeNormal, reason, message)
375388
}
376-
377389
return nil
378390
}
379391

392+
func (t *componentStatusTransformer) availableWithPhases(_ *componentTransformContext,
393+
comp *appsv1.Component, policy appsv1.ComponentAvailable) (metav1.ConditionStatus, string, string) {
394+
if comp.Status.Phase == "" {
395+
return metav1.ConditionUnknown, "Unknown", "the component phase is unknown"
396+
}
397+
phases := sets.New[string](strings.Split(strings.ToLower(*policy.WithPhases), ",")...)
398+
if phases.Has(strings.ToLower(string(comp.Status.Phase))) {
399+
return metav1.ConditionTrue, "Available", fmt.Sprintf("the component phase is %s", comp.Status.Phase)
400+
}
401+
return metav1.ConditionFalse, "Unavailable", fmt.Sprintf("the component phase is %s", comp.Status.Phase)
402+
}
403+
404+
func (t *componentStatusTransformer) availableWithRole(transCtx *componentTransformContext,
405+
_ *appsv1.Component, policy appsv1.ComponentAvailable) (metav1.ConditionStatus, string, string) {
406+
var its *workloads.InstanceSet
407+
if transCtx.RunningWorkload != nil {
408+
its = transCtx.RunningWorkload.(*workloads.InstanceSet)
409+
}
410+
if its == nil {
411+
return metav1.ConditionFalse, "Unavailable", "the workload is not present"
412+
}
413+
for _, member := range its.Status.MembersStatus {
414+
if member.ReplicaRole != nil {
415+
if strings.EqualFold(member.ReplicaRole.Name, *policy.WithRole) {
416+
return metav1.ConditionTrue, "Available", fmt.Sprintf("the role %s is present", *policy.WithRole)
417+
}
418+
}
419+
}
420+
return metav1.ConditionFalse, "Unavailable", fmt.Sprintf("the role %s is not present", *policy.WithRole)
421+
}
422+
380423
func getRunningVolumes(ctx context.Context, cli client.Client, synthesizedComp *component.SynthesizedComponent,
381424
itsObj *workloads.InstanceSet, vctName string) ([]*corev1.PersistentVolumeClaim, error) {
382425
pvcs, err := component.ListOwnedPVCs(ctx, cli, synthesizedComp.Namespace, synthesizedComp.ClusterName, synthesizedComp.Name)

controllers/apps/componentdefinition_controller.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,10 +393,20 @@ func (r *ComponentDefinitionReconciler) validateAvailable(cli client.Client, rct
393393
if cmpd.Spec.Available == nil {
394394
return nil
395395
}
396-
if cmpd.Spec.Available.WithPhases != nil && cmpd.Spec.Available.WithProbe == nil {
397-
return r.validateAvailableWithPhases(cmpd)
396+
if cmpd.Spec.Available.WithProbe != nil {
397+
return r.validateAvailableWithProbe(cmpd)
398398
}
399-
return r.validateAvailableWithProbe(cmpd)
399+
if cmpd.Spec.Available.WithPhases != nil {
400+
if err := r.validateAvailableWithPhases(cmpd); err != nil {
401+
return err
402+
}
403+
}
404+
if cmpd.Spec.Available.WithRole != nil {
405+
if err := r.validateAvailableWithRole(cmpd); err != nil {
406+
return err
407+
}
408+
}
409+
return nil
400410
}
401411

402412
func (r *ComponentDefinitionReconciler) validateAvailableWithPhases(cmpd *appsv1.ComponentDefinition) error {
@@ -418,6 +428,16 @@ func (r *ComponentDefinitionReconciler) validateAvailableWithPhases(cmpd *appsv1
418428
return nil
419429
}
420430

431+
func (r *ComponentDefinitionReconciler) validateAvailableWithRole(cmpd *appsv1.ComponentDefinition) error {
432+
role := strings.ToLower(*cmpd.Spec.Available.WithRole)
433+
for _, r := range cmpd.Spec.Roles {
434+
if strings.ToLower(r.Name) == role {
435+
return nil
436+
}
437+
}
438+
return fmt.Errorf("the role that available with role used is not defined: %s", role)
439+
}
440+
421441
func (r *ComponentDefinitionReconciler) validateAvailableWithProbe(cmpd *appsv1.ComponentDefinition) error {
422442
withProbe := cmpd.Spec.Available.WithProbe
423443
if withProbe == nil {

controllers/apps/componentdefinition_controller_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,33 @@ var _ = Describe("ComponentDefinition Controller", func() {
427427
checkObjectStatus(componentDefObj, kbappsv1.UnavailablePhase)
428428
})
429429

430+
It("with role - ok", func() {
431+
By("create a ComponentDefinition obj")
432+
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).
433+
SetRuntime(nil).
434+
AddRole("leader").
435+
SetAvailable(&kbappsv1.ComponentAvailable{
436+
WithRole: pointer.String("leader"),
437+
}).
438+
Create(&testCtx).
439+
GetObject()
440+
441+
checkObjectStatus(componentDefObj, kbappsv1.AvailablePhase)
442+
})
443+
444+
It("with role - fail", func() {
445+
By("create a ComponentDefinition obj")
446+
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).
447+
SetRuntime(nil).
448+
SetAvailable(&kbappsv1.ComponentAvailable{
449+
WithRole: pointer.String("leader"), // leader role is not defined
450+
}).
451+
Create(&testCtx).
452+
GetObject()
453+
454+
checkObjectStatus(componentDefObj, kbappsv1.UnavailablePhase)
455+
})
456+
430457
It("with probe - ok", func() {
431458
By("create a ComponentDefinition obj")
432459
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).

deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4214,6 +4214,13 @@ spec:
42144214
format: int32
42154215
type: integer
42164216
type: object
4217+
withRole:
4218+
description: |-
4219+
Specifies the role that the component will go through to be considered available.
4220+
4221+
4222+
This field is immutable once set.
4223+
type: string
42174224
type: object
42184225
configs:
42194226
description: |-

docs/developer_docs/api-reference/cluster.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4471,6 +4471,19 @@ string
44714471
</tr>
44724472
<tr>
44734473
<td>
4474+
<code>withRole</code><br/>
4475+
<em>
4476+
string
4477+
</em>
4478+
</td>
4479+
<td>
4480+
<em>(Optional)</em>
4481+
<p>Specifies the role that the component will go through to be considered available.</p>
4482+
<p>This field is immutable once set.</p>
4483+
</td>
4484+
</tr>
4485+
<tr>
4486+
<td>
44744487
<code>withProbe</code><br/>
44754488
<em>
44764489
<a href="#apps.kubeblocks.io/v1.ComponentAvailableWithProbe">

pkg/controller/component/available.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (h *AvailableEventHandler) status(ctx context.Context, cli client.Client, r
137137
func (h *AvailableEventHandler) handleEvent(event probeEvent, comp *appsv1.Component, compDef *appsv1.ComponentDefinition, its *workloads.InstanceSet) (*bool, string, error) {
138138
policy := GetComponentAvailablePolicy(compDef)
139139
if policy.WithProbe == nil || policy.WithProbe.Condition == nil {
140-
if policy.WithPhases != nil {
140+
if policy.WithPhases != nil || policy.WithRole != nil {
141141
return nil, "", nil
142142
}
143143
return nil, "", fmt.Errorf("the referenced ComponentDefinition does not have available probe defined, but we got a probe event? %s", compDef.Name)

0 commit comments

Comments
 (0)