8000 [Feature] Agency Shard Usage (#1813) · arangodb/kube-arangodb@f5ec9c7 · GitHub
[go: up one dir, main page]

Skip to content

Commit f5ec9c7

Browse files
authored
[Feature] Agency Shard Usage (#1813)
1 parent 2136397 commit f5ec9c7

File tree

8 files changed

+168
-19
lines changed

8 files changed

+168
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
44
- (Feature) (Platform) Inventory as Proto
55
- (Docs) Update Refs
6+
- (Feature) Expose Agency Shard Details
67

78
## [1.2.44](https://github.com/arangodb/kube-arangodb/tree/1.2.44) (2025-02-03)
89
- (Maintenance) Kubernetes 1.31.1 libraries

docs/integration-sidecar.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ kind: ArangoProfile
2323
metadata:
2424
name: example
2525
spec:
26-
selectors:
27-
label:
28-
matchLabels: {}
26+
selectors: {}
2927
template: ...
3028
```
3129

pkg/apis/deployment/v1/conditions.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2023-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -131,6 +131,11 @@ const (
131131

132132
// ConditionTypeSyncEnabled Define if sync is enabled
133133
ConditionTypeSyncEnabled ConditionType = "SyncEnabled"
134+
135+
// ConditionTypeSyncEnabled Define if DBServer contains any data
136+
ConditionTypeDBServerWithData ConditionType = "DBServerWithData"
137+
// ConditionTypeSyncEnabled Define if DBServer contains any active data leaders
138+
ConditionTypeDBServerWithDataLeader ConditionType = "DBServerWithDataLeader"
134139
)
135140

136141
// Condition represents one current condition of a deployment or deployment member.

pkg/apis/deployment/v2alpha1/conditions.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2023-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -131,6 +131,11 @@ const (
131131

132132
// ConditionTypeSyncEnabled Define if sync is enabled
133133
ConditionTypeSyncEnabled ConditionType = "SyncEnabled"
134+
135+
// ConditionTypeSyncEnabled Define if DBServer contains any data
136+
ConditionTypeDBServerWithData ConditionType = "DBServerWithData"
137+
// ConditionTypeSyncEnabled Define if DBServer contains any active data leaders
138+
ConditionTypeDBServerWithDataLeader ConditionType = "DBServerWithDataLeader"
134139
)
135140

136141
// Condition represents one current condition of a deployment or deployment member.

pkg/deployment/agency/state/state.go

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -65,6 +65,24 @@ type Supervision struct {
6565
Maintenance Timestamp `json:"Maintenance,omitempty"`
6666
}
6767

68+
type ShardCountDetails struct {
69+
Leader, Follower int
70+
}
71+
72+
func (s ShardCountDetails) Count() int {
73+
return s.Leader + s.Follower
74+
}
75+
76+
func (s ShardCountDetails) Add(leader bool) ShardCountDetails {
77+
if leader {
78+
s.Leader += 1
79+
} else {
80+
s.Follower += 1
81+
}
82+
83+
return s
84+
}
85+
6886
func (s State) CountShards() int {
6987
count := 0
7088

@@ -76,14 +94,14 @@ func (s State) CountShards() int {
7694
}
7795

7896
// ShardsByDBServers returns a map of DBServers and the amount of shards they have
79-
func (s State) ShardsByDBServers() map[Server]int {
80-
result := make(map[Server]int)
97+
func (s State) ShardsByDBServers() map[Server]ShardCountDetails {
98+
result := make(map[Server]ShardCountDetails)
8199

82100
for _, collections := range s.Current.Collections {
83101
for _, shards := range collections {
84102
for _, shard := range shards {
85-
for _, server := range shard.Servers {
86-
result[server]++
103+
for id, server := range shard.Servers {
104+
result[server] = result[server].Add(id == 0)
87105
}
88106
}
89107
}
@@ -101,10 +119,10 @@ func (s State) GetDBServerWithLowestShards() Server {
101119
// init first server as result
102120
if resultServer == "" {
103121
resultServer = server
104-
resultShards = shards
105-
} else if shards < resultShards {
122+
resultShards = shards.Count()
123+
} else if shards.Count() < resultShards {
106124
resultServer = server
107-
resultShards = shards
125+
resultShards = shards.Count()
108126
}
109127
}
110128
return resultServer
@@ -238,6 +256,24 @@ func (s State) PlanLeaderServers() Servers {
238256
return r
239257
}
240258

259+
// PlanServerUsage returns number of the shards and replicas by a server
260+
func (s State) PlanServerUsage(id Server) ShardCountDetails {
261+
var z ShardCountDetails
262+
for _, db := range s.Plan.Collections {
263+
for _, col := range db {
264+
for _, shards := range col.Shards {
265+
for i, shard := range shards {
266+
if shard == id {
267+
z = z.Add(i == 0)
268+
}
269+
}
270+
}
271+
}
272+
}
273+
274+
return z
275+
}
276+
241277
// PlanLeaderServersWithFailOver returns all servers which are part of the plan as a leader and can fail over
242278
func (s State) PlanLeaderServersWithFailOver() Servers {
243279
q := map[Server]bool{}

pkg/deployment/agency/state/state_test.go

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import (
2525
"encoding/json"
2626
"testing"
2727

28+
"github.com/stretchr/testify/assert"
2829
"github.com/stretchr/testify/require"
2930
)
3031

@@ -393,3 +394,70 @@ func Test_GetRebootID(t *testing.T) {
393394
require.Equal(t, 0, id)
394395
})
395396
}
397+
398+
func Test_DBServerShardCount(t *testing.T) {
399+
type testCase struct {
400+
generator Generator
401+
402+
id Server
403+
404+
expectedLeader, expectedReplicas int
405+
}
406+
407+
var testCases = map[string]testCase{
408+
"Empty": {
409+
generator: NewDatabaseRandomGenerator().RandomCollection().WithWriteConcern(1).Add().Add(),
410+
id: "A",
411+
expectedLeader: 0,
412+
expectedReplicas: 0,
413+
},
414+
"NonExisting": {
415+
generator: NewDatabaseRandomGenerator().RandomCollection().WithWriteConcern(1).
416+
WithShard().WithPlan("B", "D").Add().
417+
Add().Add(),
418+
id: "A",
419+
expectedLeader: 0,
420+
expectedReplicas: 0,
421+
},
422+
"SingleLeader": {
423+
generator: NewDatabaseRandomGenerator().RandomCollection().WithWriteConcern(1).
424+
WithShard().WithPlan("A", "B").Add().
425+
Add().Add(),
426+
id: "A",
427+
expectedLeader: 1,
428+
expectedReplicas: 0,
429+
},
430+
"SingleFollower": {
431+
generator: NewDatabaseRandomGenerator().RandomCollection().WithWriteConcern(1).
432+
WithShard().WithPlan("B", "A").Add().
433+
Add().Add(),
434+
id: "A",
435+
expectedLeader: 0,
436+
expectedReplicas: 1,
437+
},
438+
"Mixed": {
439+
generator: NewDatabaseRandomGenerator().RandomCollection().WithWriteConcern(1).
440+
WithShard().WithPlan("B", "A").Add().
441+
WithShard().WithPlan("A").Add().
442+
WithShard().WithPlan("C", "A").Add().
443+
WithShard().WithPlan("B", "E").Add().
444+
Add().Add(),
445+
id: "A",
446+
expectedLeader: 1,
447+
expectedReplicas: 2,
448+
},
449+
}
450+
451+
for n, v := range testCases {
452+
t.Run(n, func(t *testing.T) {
453+
var state State
454+
455+
v.generator(t, &state)
456+
457+
res := state.PlanServerUsage(v.id)
458+
459+
assert.Equal(t, v.expectedLeader, res.Leader)
460+
assert.Equal(t, v.expectedReplicas, res.Follower)
461+
})
462+
}
463+
}

pkg/deployment/reconcile/plan_builder_scale_funcs.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2023-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -168,10 +168,10 @@ func planBuilderScaleDownLowestShards(context PlanBuilderContext, status api.Dep
168168
// init first server as result
169169
if resultServer == "" {
170170
resultServer = server
171-
resultShards = shards
172-
} else if shards < resultShards {
171+
resultShards = shards.Count()
172+
} else if shards.Count() < resultShards {
173173
resultServer = server
174-
resultShards = shards
174+
resultShards = shards.Count()
175175
}
176176
}
177177

pkg/deployment/resources/pod_inspector.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -467,6 +467,42 @@ func (r *Resources) InspectPods(ctx context.Context, cachedStatus inspectorInter
467467
}
468468
}
469469

470+
switch group {
471+
case api.ServerGroupDBServers:
472+
if agencyCachePresent {
473+
c := agencyCache.PlanServerUsage(state.Server(memberStatus.ID))
474+
if c.Count() == 0 {
475+
if memberStatus.Conditions.Update(api.ConditionTypeDBServerWithData, false, "No Shards Assigned", "No Shards Assigned") {
476+
updateMemberStatusNeeded = true
477+
}
478+
} else {
479+
if memberStatus.Conditions.Update(api.ConditionTypeDBServerWithData, true, "Shards Assigned", fmt.Sprintf("Server with %d shards assigned", c.Count())) {
480+
updateMemberStatusNeeded = true
481+
}
482+
}
483+
if c.Leader == 0 {
484+
if memberStatus.Conditions.Update(api.ConditionTypeDBServerWithData, false, "No Shard Leaders Assigned", "No Shard Leaders Assigned") {
485+
updateMemberStatusNeeded = true
486+
}
487+
} else {
488+
if memberStatus.Conditions.Update(api.ConditionTypeDBServerWithData, true, "Shard Leaders Assigned", fmt.Sprintf("Server with %d shard leaders assigned", c.Leader)) {
489+
updateMemberStatusNeeded = true
490+
}
491+
}
492+
} else {
493+
// Let's remove data present conditions to ensure that it won't get appended
494+
if memberStatus.Conditions.Remove(api.ConditionTypeDBServerWithData) ||
495+
memberStatus.Conditions.Remove(api.ConditionTypeDBServerWithDataLeader) {
496+
updateMemberStatusNeeded = true
497+
}
498+
}
499+
default:
500+
if memberStatus.Conditions.Remove(api.ConditionTypeDBServerWithData) ||
501+
memberStatus.Conditions.Remove(api.ConditionTypeDBServerWithDataLeader) {
502+
updateMemberStatusNeeded = true
503+
}
504+
}
505+
470506
if updateMemberStatusNeeded {
471507
if err := status.Members.Update(memberStatus, group); err != nil {
472508
return errors.WithStack(err)

0 commit comments

Comments
 (0)
0