Skip to content

Commit 221d9d1

Browse files
authored
Feature/add rotate annotation (#530)
1 parent 7c64930 commit 221d9d1

File tree

7 files changed

+95
-7
lines changed

7 files changed

+95
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Change Log
22

33
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
4+
- Added annotation to rotate ArangoDeployment in secure way
45

56
## [1.0.0](https://github.com/arangodb/kube-arangodb/tree/1.0.0) (2020-03-03)
67
- Removal of v1alpha support for ArangoDeployment, ArangoDeploymentReplication, ArangoBackup

docs/design/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
- [Scaling](./scaling.md)
99
- [Status](./status.md)
1010
- [Upgrading](./upgrading.md)
11+
- [Rotating Pods](./rotating.md)
1112
- [Maintenance](./maintenance.md)

docs/design/rotating.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Rotation
2+
3+
## ArangoDeployment
4+
5+
Rotation of ArangoDeployment Pods can be triggered by Pod deletion or by annotation (safe way).
6+
7+
Using annotation Pods gonna be rotated one-by-one which will keep cluster alive.
8+
9+
Key: `deployment.arangodb.com/rotation`
10+
Value: `true`
11+
12+
To rotate ArangoDeployment Pod kubectl command can be used:
13+
`kubectl annotate pod arango-pod deployment.arangodb.com/rotation=true`

pkg/apis/deployment/annotations.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2020 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+
// Author Adam Janikowski
21+
//
22+
23+
package deployment
24+
25+
const (
26+
ArangoDeploymentAnnotationPrefix = "deployment.arangodb.com"
27+
ArangoDeploymentPodMaintenanceAnnotation = ArangoDeploymentAnnotationPrefix + "/maintenance"
28+
ArangoDeploymentPodRotateAnnotation = ArangoDeploymentAnnotationPrefix + "/rotate"
29+
)

pkg/deployment/deployment_inspector.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"context"
2727
"time"
2828

29+
"github.com/arangodb/kube-arangodb/pkg/apis/deployment"
30+
2931
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
3032
"github.com/arangodb/kube-arangodb/pkg/metrics"
3133
"github.com/arangodb/kube-arangodb/pkg/util"
@@ -37,10 +39,6 @@ var (
3739
inspectDeploymentDurationGauges = metrics.MustRegisterGaugeVec(metricsComponent, "inspect_deployment_duration", "Amount of time taken by a single inspection of a deployment (in sec)", metrics.DeploymentName)
3840
)
3941

40-
const (
41-
arangoDeploymentMaintenanceAnnotation = "deployment.arangodb.com/maintenance"
42-
)
43-
4442
// inspectDeployment inspects the entire deployment, creates
4543
// a plan to update if needed and inspects underlying resources.
4644
// This function should be called when:
@@ -74,7 +72,7 @@ func (d *Deployment) inspectDeployment(lastInterval util.Interval) util.Interval
7472
} else {
7573
// Check if maintenance annotation is set
7674
if updated != nil && updated.Annotations != nil {
77-
if v, ok := updated.Annotations[arangoDeploymentMaintenanceAnnotation]; ok && v == "true" {
75+
if v, ok := updated.Annotations[deployment.ArangoDeploymentPodMaintenanceAnnotation]; ok && v == "true" {
7876
// Disable checks if we will enter maintenance mode
7977
log.Info().Str("deployment", deploymentName).Msg("Deployment in maintenance mode")
8078
return nextInterval

pkg/deployment/reconcile/plan_builder_rotate_upgrade.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ import (
2626
"reflect"
2727
"strings"
2828

29+
"github.com/arangodb/kube-arangodb/pkg/apis/deployment"
30+
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
31+
2932
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
3033

3134
"github.com/arangodb/go-driver"
@@ -87,6 +90,17 @@ func createRotateOrUpgradePlan(log zerolog.Logger, apiObject k8sutil.APIObject,
8790
newPlan = createRotateMemberPlan(log, m, group, reason)
8891
}
8992
}
93+
94+
if !newPlan.IsEmpty() {
95+
// Only rotate/upgrade 1 pod at a time
96+
continue
97+
}
98+
99+
if pod.Annotations != nil {
100+
if _, ok := pod.Annotations[deployment.ArangoDeploymentPodRotateAnnotation]; ok {
101+
newPlan = createRotateMemberPlan(log, m, group, "Rotation flag present")
102+
}
103+
}
90104
}
91105
return nil
92106
})

pkg/util/k8sutil/map.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@
2222

2323
package k8sutil
2424

25-
import "regexp"
25+
import (
26+
"regexp"
27+
28+
"github.com/arangodb/kube-arangodb/pkg/apis/deployment"
29+
)
2630

2731
const (
2832
kubernetesAnnotationMatch = ".*kubernetes\\.io/.*"
29-
arangoAnnotationMatch = ".*arangodb\\.com/"
33+
arangoAnnotationMatch = ".*arangodb\\.com/.*"
3034
)
3135

3236
var (
@@ -50,6 +54,29 @@ func init() {
5054
arangoAnnotationRegex = r
5155
}
5256

57+
func isFilteredBlockedAnnotation(key string) bool {
58+
switch key {
59+
case deployment.ArangoDeploymentPodRotateAnnotation:
60+
return true
61+
default:
62+
return false
63+
}
64+
}
65+
66+
func filterBlockedAnnotations(m map[string]string) map[string]string {
67+
n := map[string]string{}
68+
69+
for key, value := range m {
70+
if isFilteredBlockedAnnotation(key) {
71+
continue
72+
}
73+
74+
n[key] = value
75+
}
76+
77+
return n
78+
}
79+
5380
// MergeAnnotations into one annotations map
5481
func MergeAnnotations(annotations ...map[string]string) map[string]string {
5582
ret := map[string]string{}
@@ -114,7 +141,12 @@ func filterActualAnnotations(actual, expected map[string]string) map[string]stri
114141

115142
// CompareAnnotations will compare annotations, but will ignore secured annotations which are present in
116143
// actual but not specified in expected map
144+
// It will also filter out blocked annotations
117145
func CompareAnnotations(actual, expected map[string]string) bool {
146+
return compareAnnotations(filterBlockedAnnotations(actual), filterBlockedAnnotations(expected))
147+
}
148+
149+
func compareAnnotations(actual, expected map[string]string) bool {
118150
actualFiltered := filterActualAnnotations(actual, expected)
119151

120152
if actualFiltered == nil && expected == nil {

0 commit comments

Comments
 (0)