-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy pathplan.go
452 lines (388 loc) · 15.8 KB
/
plan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v2alpha1
import (
"github.com/dchest/uniuri"
"k8s.io/apimachinery/pkg/api/equality"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/uuid"
"github.com/arangodb/kube-arangodb/pkg/util"
)
// ActionPriority define action priority
type ActionPriority int
const (
// ActionPriorityNormal define normal priority plan
ActionPriorityNormal ActionPriority = iota
// ActionPriorityHigh define high priority plan
ActionPriorityHigh
)
// ActionType is a strongly typed name for a plan action item
type ActionType string
func (a ActionType) String() string {
return string(a)
}
// Priority returns plan priority
func (a ActionType) Priority() ActionPriority {
switch a {
case ActionTypeMemberPhaseUpdate, ActionTypeMemberRIDUpdate, ActionTypeSetMemberCondition, ActionTypeSetCondition, ActionTypeSetMemberConditionV2:
return ActionPriorityHigh
default:
return ActionPriorityNormal
}
}
const (
// ActionTypeIdle causes a plan to be recalculated.
ActionTypeIdle ActionType = "Idle"
// ActionTypeAddMember causes a member to be added.
ActionTypeAddMember ActionType = "AddMember"
// ActionTypeMarkToRemoveMember marks member to be removed.
ActionTypeMarkToRemoveMember ActionType = "MarkToRemoveMember"
// ActionTypeRemoveMember causes a member to be removed.
ActionTypeRemoveMember ActionType = "RemoveMember"
// ActionTypeRecreateMember recreates member. Used when member is still owner of some shards.
ActionTypeRecreateMember ActionType = "RecreateMember"
// ActionTypeCleanOutMember causes a member to be cleaned out (dbserver only).
ActionTypeCleanOutMember ActionType = "CleanOutMember"
// ActionTypeShutdownMember causes a member to be shutdown and removed from the cluster.
ActionTypeShutdownMember ActionType = "ShutdownMember"
// ActionTypeResignLeadership causes a member to resign leadership.
ActionTypeResignLeadership ActionType = "ResignLeadership"
// ActionTypeKillMemberPod causes a pod to get delete request. It also waits until Delay finalizer will be removed.
ActionTypeKillMemberPod ActionType = "KillMemberPod"
// ActionTypeRotateMember causes a member to be shutdown and have it's pod removed.
ActionTypeRotateMember ActionType = "RotateMember"
// ActionTypeRotateStartMember causes a member to be shutdown and have it's pod removed. Do not wait to pod recover.
ActionTypeRotateStartMember ActionType = "RotateStartMember"
// ActionTypeRotateStopMember causes a member to be restored.
ActionTypeRotateStopMember ActionType = "RotateStopMember"
// ActionTypeUpgradeMember causes a member to be shutdown and have it's pod removed, restarted with AutoUpgrade option, waited until termination and the restarted again.
ActionTypeUpgradeMember ActionType = "UpgradeMember"
// ActionTypeWaitForMemberUp causes the plan to wait until the member is considered "up".
ActionTypeWaitForMemberUp ActionType = "WaitForMemberUp"
// ActionTypeWaitForMemberInSync causes the plan to wait until members are considered "up" and cluster is healthy.
ActionTypeWaitForMemberInSync ActionType = "WaitForMemberInSync"
// ActionTypeRenewTLSCertificate causes the TLS certificate of a member to be renewed.
ActionTypeRenewTLSCertificate ActionType = "RenewTLSCertificate"
// ActionTypeRenewTLSCACertificate causes the TLS CA certificate of the entire deployment to be renewed.
ActionTypeRenewTLSCACertificate ActionType = "RenewTLSCACertificate"
// ActionTypeAppendTLSCACertificate add TLS CA certificate to local truststore.
ActionTypeAppendTLSCACertificate ActionType = "AppendTLSCACertificate"
// ActionTypeCleanTLSCACertificate clean TLS CA certificate from local truststore.
ActionTypeCleanTLSCACertificate ActionType = "CleanTLSCACertificate"
// ActionTypeCleanTLSKeyfileCertificate clean server keyfile
ActionTypeCleanTLSKeyfileCertificate ActionType = "CleanTLSKeyfileCertificate"
// ActionTypeRefreshTLSKeyfileCertificate refresh server keyfile using API
ActionTypeRefreshTLSKeyfileCertificate ActionType = "RefreshTLSKeyfileCertificate"
// ActionTypeTLSKeyStatusUpdate update status with current data from deployment
ActionTypeTLSKeyStatusUpdate ActionType = "TLSKeyStatusUpdate"
// ActionTypeTLSPropagated change propagated flag
ActionTypeTLSPropagated ActionType = "TLSPropagated"
// ActionTypeUpdateTLSSNI update SNI inplace.
ActionTypeUpdateTLSSNI ActionType = "UpdateTLSSNI"
// ActionTypeSetCurrentImage causes status.CurrentImage to be updated to the image given in the action.
ActionTypeSetCurrentImage ActionType = "SetCurrentImage"
// ActionTypeSetMemberCurrentImage replace image of member to current one.
ActionTypeSetMemberCurrentImage ActionType = "SetMemberCurrentImage"
// ActionTypeDisableClusterScaling turns off scaling DBservers and coordinators
ActionTypeDisableClusterScaling ActionType = "ScalingDisabled"
// ActionTypeEnableClusterScaling turns on scaling DBservers and coordinators
ActionTypeEnableClusterScaling ActionType = "ScalingEnabled"
// ActionTypePVCResize resize event for PVC
ActionTypePVCResize ActionType = "PVCResize"
// ActionTypePVCResized waits for PVC to resize for defined time
ActionTypePVCResized ActionType = "PVCResized"
// UpToDateUpdate define up to date annotation in spec
UpToDateUpdate ActionType = "UpToDateUpdate"
// ActionTypeBackupRestore restore plan
ActionTypeBackupRestore ActionType = "BackupRestore"
// ActionTypeBackupRestoreClean restore plan
ActionTypeBackupRestoreClean ActionType = "BackupRestoreClean"
// ActionTypeEncryptionKeyAdd add new encryption key to list
ActionTypeEncryptionKeyAdd ActionType = "EncryptionKeyAdd"
// ActionTypeEncryptionKeyRemove removes encryption key to list
ActionTypeEncryptionKeyRemove ActionType = "EncryptionKeyRemove"
// ActionTypeEncryptionKeyRefresh refresh encryption keys
ActionTypeEncryptionKeyRefresh ActionType = "EncryptionKeyRefresh"
// ActionTypeEncryptionKeyStatusUpdate update status object with current encryption keys
ActionTypeEncryptionKeyStatusUpdate ActionType = "EncryptionKeyStatusUpdate"
// ActionTypeEncryptionKeyPropagated change propagated flag
ActionTypeEncryptionKeyPropagated ActionType = "EncryptionKeyPropagated"
// ActionTypeJWTStatusUpdate update status of JWT Secret
ActionTypeJWTStatusUpdate ActionType = "JWTStatusUpdate"
// ActionTypeJWTSetActive change active JWT key
ActionTypeJWTSetActive ActionType = "JWTSetActive"
// ActionTypeJWTAdd add new JWT key
ActionTypeJWTAdd ActionType = "JWTAdd"
// ActionTypeJWTClean Clean old JWT key
ActionTypeJWTClean ActionType = "JWTClean"
// ActionTypeJWTRefresh refresh jwt tokens
ActionTypeJWTRefresh ActionType = "JWTRefresh"
// ActionTypeJWTPropagated change propagated flag
ActionTypeJWTPropagated ActionType = "JWTPropagated"
// ActionTypeClusterMemberCleanup removes member from cluster
ActionTypeClusterMemberCleanup ActionType = "ClusterMemberCleanup"
// ActionTypeEnableMaintenance enables maintenance on cluster.
ActionTypeEnableMaintenance ActionType = "EnableMaintenance"
// ActionTypeDisableMaintenance disables maintenance on cluster.
ActionTypeDisableMaintenance ActionType = "DisableMaintenance"
// ActionTypeSetMaintenanceCondition sets maintenance condition.
ActionTypeSetMaintenanceCondition ActionType = "SetMaintenanceCondition"
// ActionTypeBootstrapUpdate update bootstrap status to true
ActionTypeBootstrapUpdate ActionType = "BootstrapUpdate"
// ActionTypeBootstrapSetPassword set password to the bootstrapped user
ActionTypeBootstrapSetPassword ActionType = "BootstrapSetPassword"
// ActionTypeMemberPhaseUpdate updated member phase. High priority
ActionTypeMemberPhaseUpdate ActionType = "MemberPhaseUpdate"
// ActionTypeSetMemberCondition sets member condition. It is high priority action.
ActionTypeSetMemberCondition ActionType = "SetMemberCondition"
// ActionTypeSetMemberConditionV2 sets member condition. It is high priority action.
ActionTypeSetMemberConditionV2 ActionType = "SetMemberConditionV2"
// ActionTypeSetCondition sets condition. It is high priority action.
ActionTypeSetCondition ActionType = "SetCondition"
// ActionTypeSetConditionV2 sets condition. It is high priority action.
ActionTypeSetConditionV2 ActionType = "SetConditionV2"
// ActionTypeMemberRIDUpdate updated member Run ID (UID). High priority
ActionTypeMemberRIDUpdate ActionType = "MemberRIDUpdate"
// ActionTypeArangoMemberUpdatePodSpec updates pod spec
ActionTypeArangoMemberUpdatePodSpec ActionType = "ArangoMemberUpdatePodSpec"
// ActionTypeArangoMemberUpdatePodStatus updates pod spec
ActionTypeArangoMemberUpdatePodStatus ActionType = "ArangoMemberUpdatePodStatus"
// ActionTypeLicenseSet sets server license
ActionTypeLicenseSet ActionType = "LicenseSet"
// Runtime Updates
// ActionTypeRuntimeContainerImageUpdate updates container image in runtime
ActionTypeRuntimeContainerImageUpdate ActionType = "RuntimeContainerImageUpdate"
// ActionTypeRuntimeContainerArgsLogLevelUpdate updates the container's executor arguments.
ActionTypeRuntimeContainerArgsLogLevelUpdate ActionType = "RuntimeContainerArgsLogLevelUpdate"
// Topology
ActionTypeTopologyEnable ActionType = "TopologyEnable"
ActionTypeTopologyDisable ActionType = "TopologyDisable"
ActionTypeTopologyZonesUpdate ActionType = "TopologyZonesUpdate"
ActionTypeTopologyMemberAssignment ActionType = "TopologyMemberAssignment"
// Rebalancer
ActionTypeRebalancerGenerate ActionType = "RebalancerGenerate"
ActionTypeRebalancerCheck ActionType = "RebalancerCheck"
// Resources
ActionTypeResourceSync ActionType = "ResourceSync"
// ArangoTask actions
// ActionTypePing is a mock to check if the action flow is working
ActionTypePing ActionType = "Ping"
)
const (
// MemberIDPreviousAction is used for Action.MemberID when the MemberID
// should be derived from the previous action.
MemberIDPreviousAction = "@previous"
)
const (
ParamPodUID = "PodUID"
)
// Action represents a single action to be taken to update a deployment.
type Action struct {
// ID of this action (unique for every action)
ID string `json:"id"`
// SetID define the unique ID of current action set
SetID types.UID `json:"setID,omitempty"`
// Type of action.
Type ActionType `json:"type"`
// ID reference of the member involved in this action (if any)
MemberID string `json:"memberID,omitempty"`
// Group involved in this action
Group ServerGroup `json:"group,omitempty"`
// CreationTime is set the when the action is created.
CreationTime meta.Time `json:"creationTime"`
// StartTime is set the when the action has been started, but needs to wait to be finished.
StartTime *meta.Time `json:"startTime,omitempty"`
// Reason for this action
Reason string `json:"reason,omitempty"`
// Image used in can of a SetCurrentImage action.
Image string `json:"image,omitempty"`
// Params additional parameters used for action
Params map[string]string `json:"params,omitempty"`
// Locals additional storage for local variables which are produced during the action.
Locals PlanLocals `json:"locals,omitempty"`
// ID reference of the task involved in this action (if any)
TaskID types.UID `json:"taskID,omitempty"`
}
// Equal compares two Actions
func (a Action) Equal(other Action) bool {
return a.ID == other.ID &&
a.Type == other.Type &&
a.SetID == other.SetID &&
a.MemberID == other.MemberID &&
a.Group == other.Group &&
util.TimeCompareEqual(a.CreationTime, other.CreationTime) &&
util.TimeCompareEqualPointer(a.StartTime, other.StartTime) &&
a.Reason == other.Reason &&
a.Image == other.Image &&
equality.Semantic.DeepEqual(a.Params, other.Params) &&
a.Locals.Equal(other.Locals) &&
a.TaskID == other.TaskID
}
// AddParam returns copy of action with set parameter
func (a Action) AddParam(key, value string) Action {
if a.Params == nil {
a.Params = map[string]string{}
}
a.Params[key] = value
return a
}
// GetParam returns action parameter
func (a Action) GetParam(key string) (string, bool) {
if a.Params == nil {
return "", false
}
i, ok := a.Params[key]
return i, ok
}
// NewActionSet add new SetID vale to the actions
func NewActionSet(actions ...Action) []Action {
sid := uuid.NewUUID()
for id := range actions {
actions[id].SetID = sid
}
return actions
}
// NewAction instantiates a new Action.
func NewAction(actionType ActionType, group ServerGroup, memberID string, reason ...string) Action {
a := Action{
ID: uniuri.New(),
Type: actionType,
MemberID: memberID,
Group: group,
CreationTime: meta.Now(),
}
if len(reason) != 0 {
a.Reason = reason[0]
}
return a
}
// ActionBuilder allows to generate actions based on predefined group and member id
type ActionBuilder interface {
// NewAction instantiates a new Action.
NewAction(actionType ActionType, reason ...string) Action
}
type actionBuilder struct {
group ServerGroup
memberID string
}
func (a actionBuilder) NewAction(actionType ActionType, reason ...string) Action {
return NewAction(actionType, a.group, a.memberID, reason...)
}
// NewActionBuilder create new action builder with provided group and id
func NewActionBuilder(group ServerGroup, memberID string) ActionBuilder {
return actionBuilder{
group: group,
memberID: memberID,
}
}
// SetImage sets the Image field to the given value and returns the modified
// action.
func (a Action) SetImage(image string) Action {
a.Image = image
return a
}
// SetTaskID sets the TaskID field to the given value and returns the modified action.
func (a Action) SetTaskID(taskID types.UID) Action {
a.TaskID = taskID
return a
}
// IsStarted returns true if the action has been started already.
func (a Action) IsStarted() bool {
return !a.StartTime.IsZero()
}
// AsPlan parse action list into plan
func AsPlan(a []Action) Plan {
return a
}
// Plan is a list of actions that will be taken to update a deployment.
// Only 1 action is in progress at a time. The operator will wait for that
// action to be completely and then remove the action.
type Plan []Action
// Equal compares two Plan
func (p Plan) Equal(other Plan) bool {
// For plan the order is relevant!
if len(p) != len(other) {
return false
}
for i := 0; i < len(p); i++ {
if !p[i].Equal(other[i]) {
return false
}
}
return true
}
// IsEmpty checks if plan is empty
func (p Plan) IsEmpty() bool {
return len(p) == 0
}
// Add add action at the end of plan
func (p Plan) After(action ...Action) Plan {
n := Plan{}
n = append(n, p...)
n = append(n, action...)
return n
}
// Prefix add action at the beginning of plan
func (p Plan) Before(action ...Action) Plan {
n := Plan{}
n = append(n, action...)
n = append(n, p...)
return n
}
// Prefix add action at the beginning of plan
func (p Plan) Wrap(before, after Action) Plan {
n := Plan{}
n = append(n, before)
n = append(n, p...)
n = append(n, after)
return n
}
// AfterFirst adds actions when condition will return false
func (p Plan) AfterFirst(condition func(a Action) bool, actions ...Action) Plan {
var r Plan
c := p
for {
if len(c) == 0 {
break
}
if !condition(c[0]) {
r = append(r, actions...)
r = append(r, c...)
break
}
r = append(r, c[0])
if len(c) == 1 {
break
}
c = c[1:]
}
return r
}
// Filter filter list of the actions
func (p Plan) Filter(condition func(a Action) bool) Plan {
var r Plan
for _, a := range p {
if condition(a) {
r = append(r, a)
}
}
return r
}