Skip to content

Commit 42b9a3f

Browse files
committed
init
1 parent b893218 commit 42b9a3f

10 files changed

+344
-13
lines changed

apis/apps/v1/componentdefinition_types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,18 @@ type ReplicaRole struct {
14561456
// +kubebuilder:default=false
14571457
// +optional
14581458
ParticipatesInQuorum bool `json:"participatesInQuorum"`
1459+
1460+
// IsExclusive specifies if this role can be assigned to only one Pod at a time
1461+
// within a Component. If true, the controller ensures that when a new Pod
1462+
// claims this role, any existing Pods with the same role label will have
1463+
// their labels removed immediately.
1464+
// This helps prevent "Split-Brain" scenarios during network partitions or node failures.
1465+
//
1466+
// This field is immutable once set.
1467+
//
1468+
// +kubebuilder:default=false
1469+
// +optional
1470+
IsExclusive bool `json:"isExclusive"`
14591471
}
14601472

14611473
// UpdateStrategy defines the update strategy for cluster components. This strategy determines how updates are applied

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10965,6 +10965,18 @@ spec:
1096510965
description: ReplicaRole represents a role that can be assigned
1096610966
to a component instance, defining its behavior and responsibilities.
1096710967
properties:
10968+
isExclusive:
10969+
default: false
10970+
description: |-
10971+
IsExclusive specifies if this role can be assigned to only one Pod at a time
10972+
within a Component. If true, the controller ensures that when a new Pod
10973+
claims this role, any existing Pods with the same role label will have
10974+
their labels removed immediately.
10975+
This helps prevent "Split-Brain" scenarios during network partitions or node failures.
10976+
10977+
10978+
This field is immutable once set.
10979+
type: boolean
1096810980
name:
1096910981
description: |-
1097010982
Name defines the role's unique identifier. This value is used to set the "apps.kubeblocks.io/role" label

config/crd/bases/workloads.kubeblocks.io_instances.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,18 @@ spec:
20172017
description: ReplicaRole represents a role that can be assigned
20182018
to a component instance, defining its behavior and responsibilities.
20192019
properties:
2020+
isExclusive:
2021+
default: false
2022+
description: |-
2023+
IsExclusive specifies if this role can be assigned to only one Pod at a time
2024+
within a Component. If true, the controller ensures that when a new Pod
2025+
claims this role, any existing Pods with the same role label will have
2026+
their labels removed immediately.
2027+
This helps prevent "Split-Brain" scenarios during network partitions or node failures.
2028+
2029+
2030+
This field is immutable once set.
2031+
type: boolean
20202032
name:
20212033
description: |-
20222034
Name defines the role's unique identifier. This value is used to set the "apps.kubeblocks.io/role" label

config/crd/bases/workloads.kubeblocks.io_instancesets.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3557,6 +3557,18 @@ spec:
35573557
description: ReplicaRole represents a role that can be assigned
35583558
to a component instance, defining its behavior and responsibilities.
35593559
properties:
3560+
isExclusive:
3561+
default: false
3562+
description: |-
3563+
IsExclusive specifies if this role can be assigned to only one Pod at a time
3564+
within a Component. If true, the controller ensures that when a new Pod
3565+
claims this role, any existing Pods with the same role label will have
3566+
their labels removed immediately.
3567+
This helps prevent "Split-Brain" scenarios during network partitions or node failures.
3568+
3569+
3570+
This field is immutable once set.
3571+
type: boolean
35603572
name:
35613573
description: |-
35623574
Name defines the role's unique identifier. This value is used to set the "apps.kubeblocks.io/role" label

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10965,6 +10965,18 @@ spec:
1096510965
description: ReplicaRole represents a role that can be assigned
1096610966
to a component instance, defining its behavior and responsibilities.
1096710967
properties:
10968+
isExclusive:
10969+
default: false
10970+
description: |-
10971+
IsExclusive specifies if this role can be assigned to only one Pod at a time
10972+
within a Component. If true, the controller ensures that when a new Pod
10973+
claims this role, any existing Pods with the same role label will have
10974+
their labels removed immediately.
10975+
This helps prevent "Split-Brain" scenarios during network partitions or node failures.
10976+
10977+
10978+
This field is immutable once set.
10979+
type: boolean
1096810980
name:
1096910981
description: |-
1097010982
Name defines the role's unique identifier. This value is used to set the "apps.kubeblocks.io/role" label

deploy/helm/crds/workloads.kubeblocks.io_instances.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,18 @@ spec:
20172017
description: ReplicaRole represents a role that can be assigned
20182018
to a component instance, defining its behavior and responsibilities.
20192019
properties:
2020+
isExclusive:
2021+
default: false
2022+
description: |-
2023+
IsExclusive specifies if this role can be assigned to only one Pod at a time
2024+
within a Component. If true, the controller ensures that when a new Pod
2025+
claims this role, any existing Pods with the same role label will have
2026+
their labels removed immediately.
2027+
This helps prevent "Split-Brain" scenarios during network partitions or node failures.
2028+
2029+
2030+
This field is immutable once set.
2031+
type: boolean
20202032
name:
20212033
description: |-
20222034
Name defines the role's unique identifier. This value is used to set the "apps.kubeblocks.io/role" label

deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3557,6 +3557,18 @@ spec:
35573557
description: ReplicaRole represents a role that can be assigned
35583558
to a component instance, defining its behavior and responsibilities.
35593559
properties:
3560+
isExclusive:
3561+
default: false
3562+
description: |-
3563+
IsExclusive specifies if this role can be assigned to only one Pod at a time
3564+
within a Component. If true, the controller ensures that when a new Pod
3565+
claims this role, any existing Pods with the same role label will have
3566+
their labels removed immediately.
3567+
This helps prevent "Split-Brain" scenarios during network partitions or node failures.
3568+
3569+
3570+
This field is immutable once set.
3571+
type: boolean
35603572
name:
35613573
description: |-
35623574
Name defines the role's unique identifier. This value is used to set the "apps.kubeblocks.io/role" label

docs/developer_docs/api-reference/cluster.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10374,6 +10374,23 @@ of 2 learners and 1 follower while maintaining quorum.</p>
1037410374
<p>This field is immutable once set.</p>
1037510375
</td>
1037610376
</tr>
10377+
<tr>
10378+
<td>
10379+
<code>isExclusive</code><br/>
10380+
<em>
10381+
bool
10382+
</em>
10383+
</td>
10384+
<td>
10385+
<em>(Optional)</em>
10386+
<p>IsExclusive specifies if this role can be assigned to only one Pod at a time
10387+
within a Component. If true, the controller ensures that when a new Pod
10388+
claims this role, any existing Pods with the same role label will have
10389+
their labels removed immediately.
10390+
This helps prevent &ldquo;Split-Brain&rdquo; scenarios during network partitions or node failures.</p>
10391+
<p>This field is immutable once set.</p>
10392+
</td>
10393+
</tr>
1037710394
</tbody>
1037810395
</table>
1037910396
<h3 id="apps.kubeblocks.io/v1.ReplicasLimit">ReplicasLimit

pkg/controller/instanceset/pod_role_event_handler.go

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2020
package instanceset
2121

2222
import (
23+
"context"
2324
"encoding/json"
25+
"errors"
2426
"fmt"
2527
"regexp"
2628
"slices"
@@ -236,27 +238,53 @@ func parseProbeEventMessage(reqCtx intctrlutil.RequestCtx, event *corev1.Event)
236238
return nil
237239
}
238240

239-
// updatePodRoleLabel updates pod role label when internal container role changed
240241
func updatePodRoleLabel(cli client.Client, reqCtx intctrlutil.RequestCtx,
241242
its workloads.InstanceSet, pod *corev1.Pod, roleName string, version string) error {
242-
ctx := reqCtx.Ctx
243-
roleMap := composeRoleMap(its)
244-
// role not defined in CR, ignore it
245-
roleName = strings.ToLower(roleName)
246-
243+
var (
244+
ctx = reqCtx.Ctx
245+
roleMap = composeRoleMap(its)
246+
normalizedRoleName = strings.ToLower(roleName)
247+
role, defined = roleMap[normalizedRoleName]
248+
)
247249
// update pod role label
248250
newPod := pod.DeepCopy()
249-
role, ok := roleMap[roleName]
250-
switch ok {
251-
case true:
252-
newPod.Labels[RoleLabelKey] = role.Name
253-
case false:
251+
if defined {
252+
newPod.Labels[RoleLabelKey] = normalizedRoleName
253+
} else {
254254
delete(newPod.Labels, RoleLabelKey)
255255
}
256-
257256
if newPod.Annotations == nil {
258257
newPod.Annotations = map[string]string{}
259258
}
260259
newPod.Annotations[constant.LastRoleSnapshotVersionAnnotationKey] = version
261-
return cli.Update(ctx, newPod)
260+
if err := cli.Update(ctx, newPod); err != nil {
261+
return err
262+
}
263+
264+
if role.IsExclusive {
265+
return removeExclusiveRoleLabels(ctx, cli, its, pod.Name, normalizedRoleName)
266+
}
267+
return nil
268+
}
269+
270+
func removeExclusiveRoleLabels(ctx context.Context, cli client.Client, its workloads.InstanceSet, newPodName, roleName string) error {
271+
labels := getMatchLabels(its.Name)
272+
labels[RoleLabelKey] = roleName
273+
var pods corev1.PodList
274+
if err := cli.List(ctx, &pods, client.InNamespace(its.Namespace), client.MatchingLabels(labels)); err != nil {
275+
return err
276+
}
277+
278+
var errs []error
279+
for i, pod := range pods.Items {
280+
if pod.Name == newPodName {
281+
continue
282+
}
283+
newPod := pods.Items[i].DeepCopy()
284+
delete(newPod.Labels, RoleLabelKey)
285+
if err := cli.Update(ctx, newPod); err != nil {
286+
errs = append(errs, err)
287+
}
288+
}
289+
return errors.Join(errs...)
262290
}

0 commit comments

Comments
 (0)