Skip to content

Commit 537e054

Browse files
authored
[Bugfix] Propagate Lifecycle Mount (#1139)
1 parent b90e4be commit 537e054

File tree

8 files changed

+342
-127
lines changed

8 files changed

+342
-127
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- (Feature) Add annotation to change architecture of a member
77
- (Bugfix) Prevent Member Maintenance Error log
88
- (Feature) ID ServerGroup
9+
- (Bugfix) Propagate Lifecycle Mount
910

1011
## [1.2.19](https://github.com/arangodb/kube-arangodb/tree/1.2.19) (2022-10-05)
1112
- (Bugfix) Prevent changes when UID is wrong

pkg/deployment/resources/pod_creator_arangod.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,12 @@ func addLifecycleSidecar(coreNames []string, sidecars []core.Container) error {
716716
break
717717
}
718718

719+
if !k8sutil.VolumeMountExists(sidecar.VolumeMounts, shared.LifecycleVolumeName) {
720+
sidecars[i].VolumeMounts = append(sidecars[i].VolumeMounts, k8sutil.LifecycleVolumeMount())
721+
}
722+
723+
sidecars[i].Env = k8sutil.AppendLifecycleEnv(sidecars[i].Env)
724+
719725
lifecycle, err := k8sutil.NewLifecycleFinalizers()
720726
if err != nil {
721727
return err

pkg/deployment/rotation/arangod_containers.go

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import (
2929

3030
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
3131
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
32-
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
33-
"github.com/arangodb/kube-arangodb/pkg/deployment/topology"
3432
"github.com/arangodb/kube-arangodb/pkg/util"
3533
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
3634
)
@@ -62,30 +60,14 @@ func containersCompare(ds api.DeploymentSpec, g api.ServerGroup, spec, status *c
6260

6361
g := podContainerFuncGenerator(ds, g, ac, bc)
6462

65-
if m, p, err := comparePodContainer(builder, g(compareServerContainerVolumeMounts), g(compareServerContainerProbes)); err != nil {
63+
if m, p, err := comparePodContainer(builder, g(compareServerContainerVolumeMounts), g(compareServerContainerProbes), g(compareServerContainerEnvs)); err != nil {
6664
log.Err(err).Msg("Error while getting pod diff")
6765
return SkippedRotation, nil, err
6866
} else {
6967
mode = mode.And(m)
7068
plan = append(plan, p...)
7169
}
7270

73-
if !equality.Semantic.DeepEqual(ac.Env, bc.Env) {
74-
filter := func(a, b map[string]core.EnvVar) (map[string]core.EnvVar, map[string]core.EnvVar) {
75-
for _, excludedEnv := range getExcludedEnv() {
76-
delete(a, excludedEnv)
77-
delete(b, excludedEnv)
78-
}
79-
80-
return a, b
81-
}
82-
if areEnvsEqual(ac.Env, bc.Env, filter) {
83-
// Envs are the same after filtering, but it were different before filtering, so it can be replaced.
84-
bc.Env = ac.Env
85-
mode = mode.And(SilentRotation)
86-
}
87-
}
88-
8971
if !equality.Semantic.DeepEqual(ac.EnvFrom, bc.EnvFrom) {
9072
// Check EnvFromSource differences.
9173
filter := func(a, b map[string]core.EnvFromSource) (map[string]core.EnvFromSource, map[string]core.EnvFromSource) {
@@ -113,6 +95,16 @@ func containersCompare(ds api.DeploymentSpec, g api.ServerGroup, spec, status *c
11395
bc.Image = ac.Image
11496
mode = mode.And(InPlaceRotation)
11597
}
98+
99+
g := podContainerFuncGenerator(ds, g, ac, bc)
100+
101+
if m, p, err := comparePodContainer(builder, g(compareAnyContainerVolumeMounts), g(compareAnyContainerEnvs)); err != nil {
102+
log.Err(err).Msg("Error while getting pod diff")
103+
return SkippedRotation, nil, err
104+
} else {
105+
mode = mode.And(m)
106+
plan = append(plan, p...)
107+
}
116108
}
117109

118110
if api.IsReservedServerGroupContainerName(ac.Name) {
@@ -217,27 +209,6 @@ func internalContainerLifecycleCompare(spec, status *core.Container) Mode {
217209
return SkippedRotation
218210
}
219211

220-
func areEnvsEqual(a, b []core.EnvVar, rules ...func(a, b map[string]core.EnvVar) (map[string]core.EnvVar, map[string]core.EnvVar)) bool {
221-
am := getEnvs(a)
222-
bm := getEnvs(b)
223-
224-
for _, r := range rules {
225-
am, bm = r(am, bm)
226-
}
227-
228-
return equality.Semantic.DeepEqual(am, bm)
229-
}
230-
231-
func getEnvs(e []core.EnvVar) map[string]core.EnvVar {
232-
m := map[string]core.EnvVar{}
233-
234-
for _, q := range e {
235-
m[q.Name] = q
236-
}
237-
238-
return m
239-
}
240-
241212
func areProbesEqual(a, b *core.Probe) bool {
242213
if a == nil && b == nil {
243214
return true
@@ -286,10 +257,3 @@ func createEnvsFromMap(e []core.EnvFromSource) map[string]core.EnvFromSource {
286257

287258
return m
288259
}
289-
290-
// getExcludedEnv returns environment variables which should not be compared when pod's rotation is considered.
291-
func getExcludedEnv() []string {
292-
return []string{topology.ArangoDBZone, resources.ArangoDBOverrideServerGroupEnv,
293-
resources.ArangoDBOverrideDeploymentModeEnv, resources.ArangoDBOverrideVersionEnv,
294-
resources.ArangoDBOverrideEnterpriseEnv}
295-
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package rotation
22+
23+
import (
24+
"reflect"
25+
26+
core "k8s.io/api/core/v1"
27+
28+
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
29+
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
30+
"github.com/arangodb/kube-arangodb/pkg/deployment/topology"
31+
"github.com/arangodb/kube-arangodb/pkg/util/constants"
32+
)
33+
34+
func compareServerContainerEnvs(ds api.DeploymentSpec, g api.ServerGroup, spec, status *core.Container) comparePodContainerFunc {
35+
return func(builder api.ActionBuilder) (mode Mode, plan api.Plan, err error) {
36+
specV := mapEnvs(spec)
37+
statusV := mapEnvs(status)
38+
39+
diff := getEnvDiffFromPods(specV, statusV)
40+
41+
if len(diff) == 0 {
42+
return SkippedRotation, nil, nil
43+
}
44+
45+
for k := range diff {
46+
switch k {
47+
case topology.ArangoDBZone, resources.ArangoDBOverrideServerGroupEnv,
48+
resources.ArangoDBOverrideDeploymentModeEnv, resources.ArangoDBOverrideVersionEnv,
49+
resources.ArangoDBOverrideEnterpriseEnv:
50+
// Those envs can change without restart
51+
continue
52+
case constants.EnvOperatorPodName, constants.EnvOperatorPodNamespace, constants.EnvOperatorNodeName, constants.EnvOperatorNodeNameArango:
53+
// Lifecycle envs can change without restart
54+
continue
55+
default:
56+
return GracefulRotation, nil, nil
57+
}
58+
}
59+
60+
status.Env = spec.Env
61+
return SilentRotation, nil, nil
62+
}
63+
}
64+
65+
func compareAnyContainerEnvs(ds api.DeploymentSpec, g api.ServerGroup, spec, status *core.Container) comparePodContainerFunc {
66+
return func(builder api.ActionBuilder) (mode Mode, plan api.Plan, err error) {
67+
specV := mapEnvs(spec)
68+
statusV := mapEnvs(status)
69+
70+
diff := getEnvDiffFromPods(specV, statusV)
71+
72+
if len(diff) == 0 {
73+
return SkippedRotation, nil, nil
74+
}
75+
76+
for k := range diff {
77+
switch k {
78+
case constants.EnvOperatorPodName, constants.EnvOperatorPodNamespace, constants.EnvOperatorNodeName, constants.EnvOperatorNodeNameArango:
79+
// Lifecycle envs can change without restart
80+
continue
81+
default:
82+
return GracefulRotation, nil, nil
83+
}
84+
}
85+
86+
status.Env = spec.Env
87+
return SilentRotation, nil, nil
88+
}
89+
}
90+
91+
type envDiff struct {
92+
a, b []*core.EnvVar
93+
}
94+
95+
func getEnvDiffFromPods(a, b map[string][]*core.EnvVar) map[string]envDiff {
96+
d := map[string]envDiff{}
97+
98+
for k := range a {
99+
if z, ok := b[k]; ok {
100+
if !reflect.DeepEqual(a[k], z) {
101+
d[k] = envDiff{
102+
a: a[k],
103+
b: z,
104+
}
105+
}
106+
} else {
107+
d[k] = envDiff{
108+
a: a[k],
109+
b: nil,
110+
}
111+
}
112+
}
113+
for k := range b {
114+
if _, ok := a[k]; !ok {
115+
d[k] = envDiff{
116+
a: nil,
117+
b: a[k],
118+
}
119+
}
120+
}
121+
122+
return d
123+
}
124+
125+
func mapEnvs(a *core.Container) map[string][]*core.EnvVar {
126+
n := make(map[string][]*core.EnvVar, len(a.VolumeMounts))
127+
128+
for id := range a.Env {
129+
v := &a.Env[id]
130+
131+
n[v.Name] = append(n[v.Name], v)
132+
}
133+
134+
return n
135+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package rotation
22+
23+
import (
24+
"reflect"
25+
26+
core "k8s.io/api/core/v1"
27+
28+
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
29+
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
30+
)
31+
32+
func compareServerContainerVolumeMounts(ds api.DeploymentSpec, g api.ServerGroup, spec, status *core.Container) comparePodContainerFunc {
33+
return func(builder api.ActionBuilder) (mode Mode, plan api.Plan, err error) {
34+
specV := mapVolumeMounts(spec)
35+
statusV := mapVolumeMounts(status)
36+
37+
diff := getVolumeMountsDiffFromPods(specV, statusV)
38+
39+
if len(diff) == 0 {
40+
return SkippedRotation, nil, nil
41+
}
42+
43+
for k, v := range diff {
44+
switch k {
45+
case shared.ArangoDTimezoneVolumeName:
46+
// We are fine, should be just replaced
47+
if v.a == nil {
48+
// we remove volume
49+
return GracefulRotation, nil, nil
50+
}
51+
52+
if ds.Mode.Get().ServingGroup() == g {
53+
// Always enforce on serving group
54+
return GracefulRotation, nil, nil
55+
}
56+
case shared.LifecycleVolumeName:
57+
// Do nothing
58+
default:
59+
return GracefulRotation, nil, nil
60+
}
61+
}
62+
63+
status.VolumeMounts = spec.VolumeMounts
64+
return SilentRotation, nil, nil
65+
}
66+
}
67+
68+
func compareAnyContainerVolumeMounts(ds api.DeploymentSpec, g api.ServerGroup, spec, status *core.Container) comparePodContainerFunc {
69+
return func(builder api.ActionBuilder) (mode Mode, plan api.Plan, err error) {
70+
specV := mapVolumeMounts(spec)
71+
statusV := mapVolumeMounts(status)
72+
73+
diff := getVolumeMountsDiffFromPods(specV, statusV)
74+
75+
if len(diff) == 0 {
76+
return SkippedRotation, nil, nil
77+
}
78+
79+
for k := range diff {
80+
switch k {
81+
case shared.LifecycleVolumeName:
82+
// Do nothing
83+
default:
84+
return GracefulRotation, nil, nil
85+
}
86+
}
87+
88+
status.VolumeMounts = spec.VolumeMounts
89+
return SilentRotation, nil, nil
90+
}
91+
}
92+
93+
type volumeMountDiff struct {
94+
a, b []*core.VolumeMount
95+
}
96+
97+
func getVolumeMountsDiffFromPods(a, b map[string][]*core.VolumeMount) map[string]volumeMountDiff {
98+
d := map[string]volumeMountDiff{}
99+
100+
for k := range a {
101+
if z, ok := b[k]; ok {
102+
if !reflect.DeepEqual(a[k], z) {
103+
d[k] = volumeMountDiff{
104+
a: a[k],
105+
b: z,
106+
}
107+
}
108+
} else {
109+
d[k] = volumeMountDiff{
110+
a: a[k],
111+
b: nil,
112+
}
113+
}
114+
}
115+
for k := range b {
116+
if _, ok := a[k]; !ok {
117+
d[k] = volumeMountDiff{
118+
a: nil,
119+
b: a[k],
120+
}
121+
}
122+
}
123+
124+
return d
125+
}
126+
127+
func mapVolumeMounts(a *core.Container) map[string][]*core.VolumeMount {
128+
n := make(map[string][]*core.VolumeMount, len(a.VolumeMounts))
129+
130+
for id := range a.VolumeMounts {
131+
v := &a.VolumeMounts[id]
132+
133+
n[v.Name] = append(n[v.Name], v)
134+
}
135+
136+
return n
137+
}

0 commit comments

Comments
 (0)