Skip to content

Commit dc43d67

Browse files
authored
[Bugfix] Fix 3.6 -> 3.7 upgrade (#910)
1 parent 1e9f226 commit dc43d67

File tree

8 files changed

+105
-40
lines changed

8 files changed

+105
-40
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
- (Cleanup) Reorganize main reconciliation context
1111
- (Bugfix) Unreachable condition
1212
- (Feature) Allow to disable external port (sidecar managed connection)
13+
- (Bugfix) Fix 3.6 -> 3.7 Upgrade procedure
14+
- (Bugfix) Add missing finalizer
1315

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

pkg/deployment/context_impl.go

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -289,45 +289,66 @@ func (d *Deployment) getAuth() (driver.Authentication, error) {
289289
}
290290

291291
var secret string
292-
if i := d.apiObject.Status.CurrentImage; i == nil || !features.JWTRotation().Supported(i.ArangoDBVersion, i.Enterprise) {
293-
s, err := d.GetCachedStatus().SecretReadInterface().Get(context.Background(), d.apiObject.Spec.Authentication.GetJWTSecretName(), meta.GetOptions{})
294-
if err != nil {
295-
return nil, errors.Newf("JWT Secret is missing")
296-
}
292+
var found bool
297293

298-
jwt, ok := s.Data[constants.SecretKeyToken]
299-
if !ok {
300-
return nil, errors.Newf("JWT Secret is invalid")
301-
}
294+
// Check if we can find token in folder
295+
if i := d.apiObject.Status.CurrentImage; i == nil || features.JWTRotation().Supported(i.ArangoDBVersion, i.Enterprise) {
296+
secret, found = d.getJWTFolderToken()
297+
}
298+
299+
// Fallback to token
300+
if !found {
301+
secret, found = d.getJWTToken()
302+
}
302303

303-
secret = string(jwt)
304-
} else {
304+
if !found {
305+
return nil, errors.Newf("JWT Secret is invalid")
306+
}
307+
308+
jwt, err := jwt.CreateArangodJwtAuthorizationHeader(secret, "kube-arangodb")
309+
if err != nil {
310+
return nil, errors.WithStack(err)
311+
}
312+
313+
return driver.RawAuthentication(jwt), nil
314+
}
315+
316+
func (d *Deployment) getJWTFolderToken() (string, bool) {
317+
if i := d.apiObject.Status.CurrentImage; i == nil || features.JWTRotation().Supported(i.ArangoDBVersion, i.Enterprise) {
305318
s, err := d.GetCachedStatus().SecretReadInterface().Get(context.Background(), pod.JWTSecretFolder(d.GetName()), meta.GetOptions{})
306319
if err != nil {
307320
d.deps.Log.Error().Err(err).Msgf("Unable to get secret")
308-
return nil, errors.Newf("JWT Folder Secret is missing")
321+
return "", false
309322
}
310323

311324
if len(s.Data) == 0 {
312-
return nil, errors.Newf("JWT Folder Secret is empty")
325+
return "", false
313326
}
314327

315328
if q, ok := s.Data[pod.ActiveJWTKey]; ok {
316-
secret = string(q)
329+
return string(q), true
317330
} else {
318331
for _, q := range s.Data {
319-
secret = string(q)
320-
break
332+
return string(q), true
321333
}
322334
}
323335
}
324336

325-
jwt, err := jwt.CreateArangodJwtAuthorizationHeader(secret, "kube-arangodb")
337+
return "", false
338+
}
339+
340+
func (d *Deployment) getJWTToken() (string, bool) {
341+
s, err := d.GetCachedStatus().SecretReadInterface().Get(context.Background(), d.apiObject.Spec.Authentication.GetJWTSecretName(), meta.GetOptions{})
326342
if err != nil {
327-
return nil, errors.WithStack(err)
343+
return "", false
328344
}
329345

330-
return driver.RawAuthentication(jwt), nil
346+
jwt, ok := s.Data[constants.SecretKeyToken]
347+
if !ok {
348+
return "", false
349+
}
350+
351+
return string(jwt), true
331352
}
332353

333354
// GetSyncServerClient returns a cached client for a specific arangosync server.

pkg/deployment/deployment.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,13 +474,17 @@ func (d *Deployment) updateCRStatus(ctx context.Context, force ...bool) error {
474474
attempt := 0
475475
for {
476476
attempt++
477+
q := patch.NewPatch(patch.ItemReplace(patch.NewPath("status"), d.status.last))
478+
477479
if d.apiObject.GetDeletionTimestamp() == nil {
478-
ensureFinalizers(d.apiObject)
480+
if ensureFinalizers(d.apiObject) {
481+
q.ItemAdd(patch.NewPath("metadata", "finalizers"), d.apiObject.Finalizers)
482+
}
479483
}
480484

481485
var newAPIObject *api.ArangoDeployment
482486
err := globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(ctx, func(ctxChild context.Context) error {
483-
p, err := patch.NewPatch(patch.ItemReplace(patch.NewPath("status"), d.status.last)).Marshal()
487+
p, err := q.Marshal()
484488
if err != nil {
485489
return err
486490
}

pkg/deployment/deployment_finalizers.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,17 @@ import (
3939
)
4040

4141
// ensureFinalizers adds all required finalizers to the given deployment (in memory).
42-
func ensureFinalizers(depl *api.ArangoDeployment) {
42+
func ensureFinalizers(depl *api.ArangoDeployment) bool {
4343
for _, f := range depl.GetFinalizers() {
4444
if f == constants.FinalizerDeplRemoveChildFinalizers {
4545
// Finalizer already set
46-
return
46+
return false
4747
}
4848
}
4949
// Set finalizers
5050
depl.SetFinalizers(append(depl.GetFinalizers(), constants.FinalizerDeplRemoveChildFinalizers))
51+
52+
return true
5153
}
5254

5355
// runDeploymentFinalizers goes through the list of ArangoDeployoment finalizers to see if they can be removed.

pkg/deployment/member/state.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"context"
2525
"sync"
2626

27+
"github.com/arangodb/go-driver"
2728
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
2829
"github.com/arangodb/kube-arangodb/pkg/deployment/reconciler"
2930
"github.com/arangodb/kube-arangodb/pkg/util/globals"
@@ -80,9 +81,11 @@ func (s *stateInspector) RefreshState(ctx context.Context, members api.Deploymen
8081
return
8182
}
8283

83-
if _, err := c.Version(nctx); err != nil {
84+
if v, err := c.Version(nctx); err != nil {
8485
results[id].Reachable = err
8586
return
87+
} else {
88+
results[id].Version = v
8689
}
8790
})
8891

@@ -110,6 +113,8 @@ func (s *stateInspector) MemberState(id string) (State, bool) {
110113

111114
type State struct {
112115
Reachable error
116+
117+
Version driver.VersionInfo
113118
}
114119

115120
func (s State) IsReachable() bool {

pkg/deployment/reconcile/action_arango_member_update_pod_spec.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/rs/zerolog/log"
2929

3030
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
31+
"github.com/arangodb/kube-arangodb/pkg/util"
3132
"github.com/rs/zerolog"
3233
)
3334

@@ -86,6 +87,7 @@ func (a *actionArangoMemberUpdatePodSpec) Start(ctx context.Context) (bool, erro
8687

8788
if m.Endpoint == nil || *m.Endpoint != endpoint {
8889
// Update endpoint
90+
m.Endpoint = util.NewString(endpoint)
8991
if err := status.Members.Update(m, a.action.Group); err != nil {
9092
log.Error().Err(err).Msg("Unable to update endpoint")
9193
return false, err

pkg/deployment/reconcile/plan_builder_rotate_upgrade.go

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ package reconcile
2323
import (
2424
"context"
2525

26-
"github.com/arangodb/go-driver"
2726
"github.com/arangodb/kube-arangodb/pkg/deployment/rotation"
2827

2928
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
3029

3130
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
3231

32+
"github.com/arangodb/go-driver"
3333
upgraderules "github.com/arangodb/go-upgrade-rules"
3434
"github.com/arangodb/kube-arangodb/pkg/apis/deployment"
3535
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
@@ -119,6 +119,26 @@ func createRotateOrUpgradePlanInternal(log zerolog.Logger, apiObject k8sutil.API
119119
decision := createRotateOrUpgradeDecision(log, spec, status, context)
120120

121121
if decision.IsUpgrade() {
122+
123+
for _, m := range status.Members.AsList() {
124+
// Pre-check
125+
d := decision[m.Member.ID]
126+
if !d.upgrade {
127+
continue
128+
}
129+
130+
// We have member to upgrade
131+
if d.upgradeDecision.Hold {
132+
// Holding upgrade
133+
continue
134+
}
135+
136+
if !d.upgradeDecision.UpgradeAllowed {
137+
context.CreateEvent(k8sutil.NewUpgradeNotAllowedEvent(apiObject, d.upgradeDecision.FromVersion, d.upgradeDecision.ToVersion, d.upgradeDecision.FromLicense, d.upgradeDecision.ToLicense))
138+
return nil, false
139+
}
140+
}
141+
122142
// Upgrade phase
123143
// During upgrade always get first member which needs to be upgraded
124144
for _, m := range status.Members.AsList() {
@@ -175,7 +195,7 @@ func createRotateOrUpgradePlanInternal(log zerolog.Logger, apiObject k8sutil.API
175195
}
176196

177197
if m.Member.Conditions.IsTrue(api.ConditionTypeRestart) {
178-
return createRotateMemberPlan(log, m.Member, m.Group, "Restart flag present"), false
198+
return createRotateMemberPlan(log, m.Member, m.Group, spec, "Restart flag present"), false
179199
}
180200
arangoMember, ok := cachedStatus.ArangoMember(m.Member.ArangoMemberName(apiObject.GetName(), m.Group))
181201
if !ok {
@@ -402,18 +422,15 @@ func createUpgradeMemberPlan(log zerolog.Logger, member api.MemberStatus,
402422
Str("reason", reason).
403423
Str("action", string(upgradeAction)).
404424
Msg("Creating upgrade plan")
405-
var plan = api.Plan{
406-
api.NewAction(api.ActionTypeCleanTLSKeyfileCertificate, group, member.ID, "Remove server keyfile and enforce renewal/recreation"),
425+
426+
plan := createRotateMemberPlanWithAction(member, group, upgradeAction, spec, reason)
427+
428+
if member.Image == nil || member.Image.Image != spec.GetImage() {
429+
plan = plan.Before(api.NewAction(api.ActionTypeSetMemberCurrentImage, group, member.ID, reason).SetImage(spec.GetImage()))
407430
}
408431
if status.CurrentImage == nil || status.CurrentImage.Image != spec.GetImage() {
409-
plan = plan.After(api.NewAction(api.ActionTypeSetCurrentImage, group, "", reason).SetImage(spec.GetImage()))
432+
plan = plan.Before(api.NewAction(api.ActionTypeSetCurrentImage, group, "", reason).SetImage(spec.GetImage()))
410433
}
411-
if member.Image == nil || member.Image.Image != spec.GetImage() {
412-
plan = plan.After(api.NewAction(api.ActionTypeSetMemberCurrentImage, group, member.ID, reason).SetImage(spec.GetImage()))
413-
}
414-
415-
plan = plan.After(api.NewAction(upgradeAction, group, member.ID, reason),
416-
api.NewAction(api.ActionTypeWaitForMemberUp, group, member.ID))
417434

418435
return withSecureWrap(member, group, spec, plan...)
419436
}

pkg/deployment/reconcile/plan_builder_utils.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,32 @@ import (
3434
// createRotateMemberPlan creates a plan to rotate (stop-recreate-start) an existing
3535
// member.
3636
func createRotateMemberPlan(log zerolog.Logger, member api.MemberStatus,
37-
group api.ServerGroup, reason string) api.Plan {
37+
group api.ServerGroup, spec api.DeploymentSpec, reason string) api.Plan {
3838
log.Debug().
3939
Str("id", member.ID).
4040
Str("role", group.AsRole()).
4141
Str("reason", reason).
4242
Msg("Creating rotation plan")
43-
plan := api.Plan{
43+
return createRotateMemberPlanWithAction(member, group, api.ActionTypeRotateMember, spec, reason)
44+
}
45+
46+
// createRotateMemberPlanWithAction creates a plan to rotate (stop-<action>>-start) an existing
47+
// member.
48+
func createRotateMemberPlanWithAction(member api.MemberStatus,
49+
group api.ServerGroup, action api.ActionType, spec api.DeploymentSpec, reason string) api.Plan {
50+
51+
var plan = api.Plan{
4452
api.NewAction(api.ActionTypeCleanTLSKeyfileCertificate, group, member.ID, "Remove server keyfile and enforce renewal/recreation"),
45-
api.NewAction(api.ActionTypeResignLeadership, group, member.ID, reason),
53+
}
54+
plan = withSecureWrap(member, group, spec, plan...)
55+
56+
plan = plan.After(
4657
withMemberPodUID(member, api.NewAction(api.ActionTypeKillMemberPod, group, member.ID, reason)),
47-
withMemberPodUID(member, api.NewAction(api.ActionTypeRotateMember, group, member.ID, reason)),
58+
withMemberPodUID(member, api.NewAction(action, group, member.ID, reason)),
4859
api.NewAction(api.ActionTypeWaitForMemberUp, group, member.ID),
4960
api.NewAction(api.ActionTypeWaitForMemberInSync, group, member.ID),
50-
}
61+
)
62+
5163
return plan
5264
}
5365

0 commit comments

Comments
 (0)