Skip to content

Commit 281f28f

Browse files
authored
[Feature] Topology Discovery (#835)
1 parent 1b66d2e commit 281f28f

File tree

6 files changed

+205
-9
lines changed

6 files changed

+205
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Add new admin commands to fetch agency dump and agency state
77
- Add Graceful shutdown as finalizer (supports kubectl delete)
88
- Add Watch to Lifecycle command
9+
- Add Topology Discovery
910

1011
## [1.2.4](https://github.com/arangodb/kube-arangodb/tree/1.2.4) (2021-10-22)
1112
- Replace `beta.kubernetes.io/arch` Pod label with `kubernetes.io/arch` using Silent Rotation

pkg/deployment/reconcile/plan_builder_high.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func createHighPlan(ctx context.Context, log zerolog.Logger, apiObject k8sutil.A
8989
ApplyIfEmpty(createCleanOutPlan).
9090
ApplyIfEmpty(updateMemberUpdateConditionsPlan).
9191
ApplyIfEmpty(updateMemberRotationConditionsPlan).
92+
ApplyIfEmpty(createTopologyMemberUpdatePlan).
9293
ApplyIfEmpty(createTopologyMemberConditionPlan).
9394
Plan(), true
9495
}

pkg/deployment/reconcile/plan_builder_topology.community.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ func createTopologyEnablementPlan(ctx context.Context,
3737
cachedStatus inspectorInterface.Inspector, context PlanBuilderContext) api.Plan {
3838
return nil
3939
}
40+
func createTopologyMemberUpdatePlan(ctx context.Context,
41+
log zerolog.Logger, apiObject k8sutil.APIObject,
42+
spec api.DeploymentSpec, status api.DeploymentStatus,
43+
cachedStatus inspectorInterface.Inspector, context PlanBuilderContext) api.Plan {
44+
return nil
45+
}
4046

4147
func createTopologyMemberConditionPlan(ctx context.Context,
4248
log zerolog.Logger, apiObject k8sutil.APIObject,

pkg/deployment/rotation/arangod_containers.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ package rotation
2626
import (
2727
"strings"
2828

29+
"github.com/arangodb/kube-arangodb/pkg/deployment/topology"
30+
2931
"k8s.io/apimachinery/pkg/api/equality"
3032

3133
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
@@ -50,15 +52,26 @@ func containersCompare(_ api.DeploymentSpec, _ api.ServerGroup, spec, status *co
5052
for id := range a {
5153
if ac, bc := &a[id], &b[id]; ac.Name == bc.Name {
5254
if ac.Name == api.ServerGroupReservedContainerNameServer {
53-
if !isOnlyLogLevelChanged(ac.Command, bc.Command) {
54-
continue
55-
}
55+
if isOnlyLogLevelChanged(ac.Command, bc.Command) {
56+
plan = append(plan, builder.NewAction(api.ActionTypeRuntimeContainerArgsLogLevelUpdate).
57+
AddParam(ContainerName, ac.Name))
5658

57-
plan = append(plan, builder.NewAction(api.ActionTypeRuntimeContainerArgsLogLevelUpdate).
58-
AddParam(ContainerName, ac.Name))
59+
bc.Command = ac.Command
60+
mode = mode.And(InPlaceRotation)
61+
}
5962

60-
bc.Command = ac.Command
61-
mode = mode.And(InPlaceRotation)
63+
if !equality.Semantic.DeepEqual(ac.Env, bc.Env) {
64+
if areEnvsEqual(ac.Env, bc.Env, func(a, b map[string]core.EnvVar) (map[string]core.EnvVar, map[string]core.EnvVar) {
65+
if _, ok := a[topology.ArangoDBZone]; !ok {
66+
delete(b, topology.ArangoDBZone)
67+
}
68+
69+
return a, b
70+
}) {
71+
bc.Env = ac.Env
72+
mode = mode.And(SilentRotation)
73+
}
74+
}
6275
} else {
6376
if ac.Image != bc.Image {
6477
// Image changed
@@ -162,3 +175,24 @@ func internalContainerLifecycleCompare(spec, status *core.Container) Mode {
162175

163176
return SkippedRotation
164177
}
178+
179+
func areEnvsEqual(a, b []core.EnvVar, rules ...func(a, b map[string]core.EnvVar) (map[string]core.EnvVar, map[string]core.EnvVar)) bool {
180+
am := getEnvs(a)
181+
bm := getEnvs(b)
182+
183+
for _, r := range rules {
184+
am, bm = r(am, bm)
185+
}
186+
187+
return equality.Semantic.DeepEqual(am, bm)
188+
}
189+
190+
func getEnvs(e []core.EnvVar) map[string]core.EnvVar {
191+
m := map[string]core.EnvVar{}
192+
193+
for _, q := range e {
194+
m[q.Name] = q
195+
}
196+
197+
return m
198+
}

pkg/deployment/rotation/arangod_test.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ package rotation
2525
import (
2626
"testing"
2727

28+
"github.com/arangodb/kube-arangodb/pkg/deployment/topology"
29+
2830
core "k8s.io/api/core/v1"
2931
)
3032

@@ -177,3 +179,150 @@ func Test_ArangoD_Affinity(t *testing.T) {
177179

178180
runTestCases(t)(testCases...)
179181
}
182+
183+
func Test_ArangoD_Labels(t *testing.T) {
184+
testCases := []TestCase{
185+
{
186+
name: "Add label",
187+
188+
spec: buildPodSpec(func(pod *core.PodTemplateSpec) {
189+
pod.Labels = map[string]string{}
190+
}),
191+
192+
status: buildPodSpec(func(pod *core.PodTemplateSpec) {
193+
pod.Labels = map[string]string{
194+
"A": "B",
195+
}
196+
}),
197+
198+
expectedMode: SkippedRotation,
199+
},
200+
{
201+
name: "Remove label",
202+
203+
spec: buildPodSpec(func(pod *core.PodTemplateSpec) {
204+
pod.Labels = map[string]string{
205+
"A": "B",
206+
}
207+
}),
208+
209+
status: buildPodSpec(func(pod *core.PodTemplateSpec) {
210+
pod.Labels = map[string]string{}
211+
}),
212+
213+
expectedMode: SkippedRotation,
214+
},
215+
{
216+
name: "Change label",
217+
218+
spec: buildPodSpec(func(pod *core.PodTemplateSpec) {
219+
pod.Labels = map[string]string{
220+
"A": "A",
221+
}
222+
}),
223+
224+
status: buildPodSpec(func(pod *core.PodTemplateSpec) {
225+
pod.Labels = map[string]string{
226+
"A": "B",
227+
}
228+
}),
229+
230+
expectedMode: SkippedRotation,
231+
},
232+
}
233+
234+
runTestCases(t)(testCases...)
235+
}
236+
237+
func Test_ArangoD_Envs_Zone(t *testing.T) {
238+
testCases := []TestCase{
239+
{
240+
name: "Add Zone env",
241+
242+
spec: buildPodSpec(addContainer("server", func(c *core.Container) {
243+
c.Env = []core.EnvVar{}
244+
})),
245+
246+
status: buildPodSpec(addContainer("server", func(c *core.Container) {
247+
c.Env = []core.EnvVar{
248+
{
249+
Name: topology.ArangoDBZone,
250+
Value: "A",
251+
},
252+
}
253+
})),
254+
255+
expectedMode: SilentRotation,
256+
},
257+
{
258+
name: "Remove Zone env",
259+
260+
spec: buildPodSpec(addContainer("server", func(c *core.Container) {
261+
c.Env = []core.EnvVar{
262+
{
263+
Name: topology.ArangoDBZone,
264+
Value: "A",
265+
},
266+
}
267+
})),
268+
269+
status: buildPodSpec(addContainer("server", func(c *core.Container) {
270+
c.Env = []core.EnvVar{}
271+
})),
272+
273+
expectedMode: GracefulRotation,
274+
},
275+
{
276+
name: "Update Zone env",
277+
278+
spec: buildPodSpec(addContainer("server", func(c *core.Container) {
279+
c.Env = []core.EnvVar{
280+
{
281+
Name: topology.ArangoDBZone,
282+
Value: "A",
283+
},
284+
}
285+
})),
286+
287+
status: buildPodSpec(addContainer("server", func(c *core.Container) {
288+
c.Env = []core.EnvVar{
289+
{
290+
Name: topology.ArangoDBZone,
291+
Value: "B",
292+
},
293+
}
294+
})),
295+
296+
expectedMode: GracefulRotation,
297+
},
298+
{
299+
name: "Update other env",
300+
301+
spec: buildPodSpec(addContainer("server", func(c *core.Container) {
302+
c.Env = []core.EnvVar{
303+
{
304+
Name: "Q",
305+
Value: "A",
306+
},
307+
{
308+
Name: topology.ArangoDBZone,
309+
Value: "A",
310+
},
311+
}
312+
})),
313+
314+
status: buildPodSpec(addContainer("server", func(c *core.Container) {
315+
c.Env = []core.EnvVar{
316+
{
317+
Name: topology.ArangoDBZone,
318+
Value: "A",
319+
},
320+
}
321+
})),
322+
323+
expectedMode: GracefulRotation,
324+
},
325+
}
326+
327+
runTestCases(t)(testCases...)
328+
}

pkg/deployment/rotation/compare.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package rotation
2222

2323
import (
24+
"encoding/json"
25+
2426
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
2527
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
2628
"github.com/rs/zerolog"
@@ -88,10 +90,13 @@ func compare(log zerolog.Logger, deploymentSpec api.DeploymentSpec, member api.M
8890
}
8991

9092
if spec.RotationNeeded(newStatus) {
93+
specData, _ := json.Marshal(spec)
94+
statusData, _ := json.Marshal(newStatus)
95+
9196
log.Info().Str("before", spec.PodSpecChecksum).
9297
Str("id", member.ID).
93-
Interface("spec", spec).
94-
Interface("status", newStatus).
98+
Str("spec", string(specData)).
99+
Str("status", string(statusData)).
95100
Msg("Pod needs rotation - templates does not match")
96101

97102
return GracefulRotation, nil, nil

0 commit comments

Comments
 (0)