Skip to content

Commit a4e48c3

Browse files
authored
[Bugfix] Add grecefulness to kill action (#912)
1 parent d51acfd commit a4e48c3

29 files changed

+320
-153
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- (Feature) Allow to disable external port (sidecar managed connection)
1313
- (Bugfix) Fix 3.6 -> 3.7 Upgrade procedure
1414
- (Bugfix) Add missing finalizer
15+
- (Bugfix) Add graceful to kill command
1516

1617
## [1.2.7](https://github.com/arangodb/kube-arangodb/tree/1.2.7) (2022-01-17)
1718
- Add Plan BackOff functionality

pkg/deployment/actions/wrapper.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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 actions
22+
23+
import api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
24+
25+
func NewAction(actionType api.ActionType, group api.ServerGroup, member api.MemberStatus, reason ...string) api.Action {
26+
return actionWrap(api.NewAction(actionType, group, member.ID, reason...), &member, actionWrapMemberUID)
27+
}
28+
29+
func NewClusterAction(actionType api.ActionType, reason ...string) api.Action {
30+
m := api.MemberStatus{}
31+
return NewAction(actionType, api.ServerGroupUnknown, m, reason...)
32+
}
33+
34+
func NewActionBuilderWrap(group api.ServerGroup, member api.MemberStatus) api.ActionBuilder {
35+
return &actionBuilderWrap{
36+
group: group,
37+
member: member,
38+
}
39+
}
40+
41+
type actionBuilderWrap struct {
42+
group api.ServerGroup
43+
member api.MemberStatus
44+
}
45+
46+
func (a actionBuilderWrap) NewAction(actionType api.ActionType, reason ...string) api.Action {
47+
return NewAction(actionType, a.group, a.member, reason...)
48+
}
49+
50+
func actionWrap(a api.Action, member *api.MemberStatus, wrap ...actionWrapper) api.Action {
51+
for _, w := range wrap {
52+
a = w(a, member)
53+
}
54+
55+
return a
56+
}
57+
58+
func actionWrapMemberUID(a api.Action, member *api.MemberStatus) api.Action {
59+
switch a.Type {
60+
case api.ActionTypeShutdownMember, api.ActionTypeKillMemberPod, api.ActionTypeRotateStartMember, api.ActionTypeUpgradeMember:
61+
if q := member.PodUID; q != "" {
62+
return a.AddParam(api.ParamPodUID, string(q))
63+
}
64+
return a
65+
default:
66+
return a
67+
}
68+
}
69+
70+
type actionWrapper func(a api.Action, member *api.MemberStatus) api.Action

pkg/deployment/reconcile/action.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,30 @@ type ActionStartFailureGracePeriod interface {
9191
StartFailureGracePeriod() time.Duration
9292
}
9393

94+
func wrapActionStartFailureGracePeriod(action Action, failureGracePeriod time.Duration) Action {
95+
return &actionStartFailureGracePeriod{
96+
Action: action,
97+
failureGracePeriod: failureGracePeriod,
98+
}
99+
}
100+
101+
func withActionStartFailureGracePeriod(in actionFactory, failureGracePeriod time.Duration) actionFactory {
102+
return func(log zerolog.Logger, action api.Action, actionCtx ActionContext) Action {
103+
return wrapActionStartFailureGracePeriod(in(log, action, actionCtx), failureGracePeriod)
104+
}
105+
}
106+
107+
var _ ActionStartFailureGracePeriod = &actionStartFailureGracePeriod{}
108+
109+
type actionStartFailureGracePeriod struct {
110+
Action
111+
failureGracePeriod time.Duration
112+
}
113+
114+
func (a actionStartFailureGracePeriod) StartFailureGracePeriod() time.Duration {
115+
return a.failureGracePeriod
116+
}
117+
94118
func getStartFailureGracePeriod(a Action) time.Duration {
95119
if c, ok := a.(ActionStartFailureGracePeriod); !ok {
96120
return 0
@@ -118,27 +142,27 @@ func getActionPlanAppender(a Action, plan api.Plan) (api.Plan, bool) {
118142
type actionFactory func(log zerolog.Logger, action api.Action, actionCtx ActionContext) Action
119143

120144
var (
121-
actions = map[api.ActionType]actionFactory{}
122-
actionsLock sync.Mutex
145+
definedActions = map[api.ActionType]actionFactory{}
146+
definedActionsLock sync.Mutex
123147
)
124148

125149
func registerAction(t api.ActionType, f actionFactory) {
126-
actionsLock.Lock()
127-
defer actionsLock.Unlock()
150+
definedActionsLock.Lock()
151+
defer definedActionsLock.Unlock()
128152

129-
_, ok := actions[t]
153+
_, ok := definedActions[t]
130154
if ok {
131155
panic(fmt.Sprintf("Action already defined %s", t))
132156
}
133157

134-
actions[t] = f
158+
definedActions[t] = f
135159
}
136160

137161
func getActionFactory(t api.ActionType) (actionFactory, bool) {
138-
actionsLock.Lock()
139-
defer actionsLock.Unlock()
162+
definedActionsLock.Lock()
163+
defer definedActionsLock.Unlock()
140164

141-
f, ok := actions[t]
165+
f, ok := definedActions[t]
142166
return f, ok
143167
}
144168

pkg/deployment/reconcile/action_add_member.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3030

3131
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
32+
"github.com/arangodb/kube-arangodb/pkg/deployment/actions"
3233
"github.com/rs/zerolog"
3334
"github.com/rs/zerolog/log"
3435
)
@@ -81,11 +82,11 @@ func (a *actionAddMember) ActionPlanAppender(current api.Plan) (api.Plan, bool)
8182
var app api.Plan
8283

8384
if _, ok := a.action.Params[api.ActionTypeWaitForMemberUp.String()]; ok {
84-
app = append(app, api.NewAction(api.ActionTypeWaitForMemberUp, a.action.Group, a.newMemberID, "Wait for member in sync after creation"))
85+
app = append(app, actions.NewAction(api.ActionTypeWaitForMemberUp, a.action.Group, withPredefinedMember(a.newMemberID), "Wait for member in sync after creation"))
8586
}
8687

8788
if _, ok := a.action.Params[api.ActionTypeWaitForMemberInSync.String()]; ok {
88-
app = append(app, api.NewAction(api.ActionTypeWaitForMemberInSync, a.action.Group, a.newMemberID, "Wait for member in sync after creation"))
89+
app = append(app, actions.NewAction(api.ActionTypeWaitForMemberInSync, a.action.Group, withPredefinedMember(a.newMemberID), "Wait for member in sync after creation"))
8990
}
9091

9192
if len(app) > 0 {

pkg/deployment/reconcile/action_rotate_member.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
)
3535

3636
func init() {
37-
registerAction(api.ActionTypeRotateMember, newRotateMemberAction)
37+
registerAction(api.ActionTypeRotateMember, withActionStartFailureGracePeriod(newRotateMemberAction, time.Minute))
3838
}
3939

4040
// newRotateMemberAction creates a new Action that implements the given
@@ -109,7 +109,3 @@ func (a *actionRotateMember) CheckProgress(ctx context.Context) (bool, bool, err
109109
}
110110
return true, false, nil
111111
}
112-
113-
func (a *actionRotateMember) StartFailureGracePeriod() time.Duration {
114-
return 30 * time.Second
115-
}

pkg/deployment/reconcile/action_rotate_start_member.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ import (
2626
"github.com/rs/zerolog"
2727
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
2828

29+
"time"
30+
2931
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
3032
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3133
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
3234
)
3335

3436
func init() {
35-
registerAction(api.ActionTypeRotateStartMember, newRotateStartMemberAction)
37+
registerAction(api.ActionTypeRotateStartMember, withActionStartFailureGracePeriod(newRotateStartMemberAction, time.Minute))
3638
}
3739

3840
// newRotateStartMemberAction creates a new Action that implements the given

pkg/deployment/reconcile/action_shutdown_member.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ import (
2525

2626
"github.com/arangodb/kube-arangodb/pkg/util/errors"
2727

28+
"time"
29+
2830
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
2931
"github.com/rs/zerolog"
3032
)
3133

3234
func init() {
33-
registerAction(api.ActionTypeShutdownMember, newShutdownMemberAction)
35+
registerAction(api.ActionTypeShutdownMember, withActionStartFailureGracePeriod(newShutdownMemberAction, time.Minute))
3436
}
3537

3638
// newShutdownMemberAction creates a new Action that implements the given
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 reconcile
22+
23+
import (
24+
"testing"
25+
"time"
26+
27+
"github.com/stretchr/testify/require"
28+
)
29+
30+
type gracefulAction struct {
31+
actionEmpty
32+
33+
graceful time.Duration
34+
}
35+
36+
func (g gracefulAction) StartFailureGracePeriod() time.Duration {
37+
return g.graceful
38+
}
39+
40+
var _ ActionStartFailureGracePeriod = gracefulAction{}
41+
42+
func Test_GracefulTimeouts(t *testing.T) {
43+
t.Run("Default", func(t *testing.T) {
44+
require.EqualValues(t, 0, getStartFailureGracePeriod(actionEmpty{}))
45+
})
46+
t.Run("Set", func(t *testing.T) {
47+
require.EqualValues(t, time.Second, getStartFailureGracePeriod(gracefulAction{
48+
graceful: time.Second,
49+
}))
50+
})
51+
t.Run("Override", func(t *testing.T) {
52+
require.EqualValues(t, time.Minute, getStartFailureGracePeriod(wrapActionStartFailureGracePeriod(gracefulAction{
53+
graceful: time.Second,
54+
}, time.Minute)))
55+
})
56+
}

pkg/deployment/reconcile/helper_wrap.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package reconcile
2222

2323
import (
2424
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
25+
"github.com/arangodb/kube-arangodb/pkg/deployment/actions"
2526
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
2627
)
2728

@@ -30,38 +31,38 @@ func withMaintenance(plan ...api.Action) api.Plan {
3031
return plan
3132
}
3233

33-
return withMaintenanceStart(plan...).After(api.NewAction(api.ActionTypeDisableMaintenance, api.ServerGroupUnknown, "", "Disable maintenance after actions"))
34+
return withMaintenanceStart(plan...).After(actions.NewClusterAction(api.ActionTypeDisableMaintenance, "Disable maintenance after actions"))
3435
}
3536
func withMaintenanceStart(plan ...api.Action) api.Plan {
3637
if !features.Maintenance().Enabled() {
3738
return plan
3839
}
3940

4041
return api.AsPlan(plan).Before(
41-
api.NewAction(api.ActionTypeEnableMaintenance, api.ServerGroupUnknown, "", "Enable maintenance before actions"),
42-
api.NewAction(api.ActionTypeSetMaintenanceCondition, api.ServerGroupUnknown, "", "Enable maintenance before actions"))
42+
actions.NewClusterAction(api.ActionTypeEnableMaintenance, "Enable maintenance before actions"),
43+
actions.NewClusterAction(api.ActionTypeSetMaintenanceCondition, "Enable maintenance before actions"))
4344
}
4445

4546
func withResignLeadership(group api.ServerGroup, member api.MemberStatus, reason string, plan ...api.Action) api.Plan {
4647
if member.Image == nil {
4748
return plan
4849
}
4950

50-
return api.AsPlan(plan).Before(api.NewAction(api.ActionTypeResignLeadership, group, member.ID, reason))
51+
return api.AsPlan(plan).Before(actions.NewAction(api.ActionTypeResignLeadership, group, member, reason))
5152
}
5253

5354
func cleanOutMember(group api.ServerGroup, m api.MemberStatus) api.Plan {
5455
var plan api.Plan
5556

5657
if group == api.ServerGroupDBServers {
5758
plan = append(plan,
58-
api.NewAction(api.ActionTypeCleanOutMember, group, m.ID),
59+
actions.NewAction(api.ActionTypeCleanOutMember, group, m),
5960
)
6061
}
6162
plan = append(plan,
62-
api.NewAction(api.ActionTypeKillMemberPod, group, m.ID),
63-
api.NewAction(api.ActionTypeShutdownMember, group, m.ID),
64-
api.NewAction(api.ActionTypeRemoveMember, group, m.ID),
63+
actions.NewAction(api.ActionTypeKillMemberPod, group, m),
64+
actions.NewAction(api.ActionTypeShutdownMember, group, m),
65+
actions.NewAction(api.ActionTypeRemoveMember, group, m),
6566
)
6667

6768
return plan

pkg/deployment/reconcile/plan_builder_bootstrap.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"context"
2525

2626
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
27+
"github.com/arangodb/kube-arangodb/pkg/deployment/actions"
2728
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
2829
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
2930
"github.com/rs/zerolog"
@@ -54,8 +55,8 @@ func createBootstrapPlan(ctx context.Context,
5455
}
5556
}
5657

57-
return api.Plan{api.NewAction(api.ActionTypeBootstrapSetPassword, api.ServerGroupUnknown, "", "Updating password").AddParam("user", user)}
58+
return api.Plan{actions.NewClusterAction(api.ActionTypeBootstrapSetPassword, "Updating password").AddParam("user", user)}
5859
}
5960

60-
return api.Plan{api.NewAction(api.ActionTypeBootstrapUpdate, api.ServerGroupUnknown, "", "Finalizing bootstrap")}
61+
return api.Plan{actions.NewClusterAction(api.ActionTypeBootstrapUpdate, "Finalizing bootstrap")}
6162
}

0 commit comments

Comments
 (0)