Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- Update 'github.com/arangodb/arangosync-client' dependency to v0.7.0
- Add HighPriorityPlan to ArangoDeployment Status
- Add Pending Member phase

## [1.2.1](https://github.com/arangodb/kube-arangodb/tree/1.2.1) (2021-07-28)
- Fix ArangoMember race with multiple ArangoDeployments within single namespace
Expand Down
17 changes: 17 additions & 0 deletions pkg/apis/deployment/v1/member_phase.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type MemberPhase string
const (
// MemberPhaseNone indicates that the state is not set yet
MemberPhaseNone MemberPhase = ""
// MemberPhasePending indicates that member propagation has been started
MemberPhasePending MemberPhase = "Pending"
// MemberPhaseCreated indicates that all resources needed for the member have been created
MemberPhaseCreated MemberPhase = "Created"
// MemberPhaseFailed indicates that the member is gone beyond hope of recovery. It must be replaced with a new member.
Expand All @@ -48,6 +50,11 @@ const (
MemberPhaseUpgrading MemberPhase = "Upgrading"
)

// IsPending returns true when given phase == "" OR "Pending"
func (p MemberPhase) IsPending() bool {
return p == MemberPhaseNone || p == MemberPhasePending
}

// IsFailed returns true when given phase == "Failed"
func (p MemberPhase) IsFailed() bool {
return p == MemberPhaseFailed
Expand All @@ -62,3 +69,13 @@ func (p MemberPhase) IsCreatedOrDrain() bool {
func (p MemberPhase) String() string {
return string(p)
}

// GetPhase parses string into phase
func GetPhase(phase string) (MemberPhase, bool) {
switch p := MemberPhase(phase); p {
case MemberPhaseNone, MemberPhasePending, MemberPhaseCreated, MemberPhaseFailed, MemberPhaseCleanOut, MemberPhaseDrain, MemberPhaseResign, MemberPhaseShuttingDown, MemberPhaseRotating, MemberPhaseRotateStart, MemberPhaseUpgrading:
return p, true
default:
return "", false
}
}
4 changes: 4 additions & 0 deletions pkg/apis/deployment/v1/member_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type MemberStatus struct {
// ID holds the unique ID of the member.
// This id is also used within the ArangoDB cluster to identify this server.
ID string `json:"id"`
// RID holds the ID of the member run.
// Value is updated in Pending Phase.
RID types.UID `json:"rid,omitempty"`
// Phase holds the current lifetime phase of this member
Phase MemberPhase `json:"phase"`
// CreatedAt holds the creation timestamp of this member.
Expand Down Expand Up @@ -82,6 +85,7 @@ type MemberStatus struct {
// Equal checks for equality
func (s MemberStatus) Equal(other MemberStatus) bool {
return s.ID == other.ID &&
s.RID == other.RID &&
s.Phase == other.Phase &&
util.TimeCompareEqual(s.CreatedAt, other.CreatedAt) &&
s.PersistentVolumeClaimName == other.PersistentVolumeClaimName &&
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/deployment/v1/member_status_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (l MemberStatusList) SelectMemberToRemove() (MemberStatus, error) {
}
// Try to find a not ready member
for _, m := range l {
if m.Phase == MemberPhaseNone {
if m.Phase.IsPending() {
return m, nil
}
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/deployment/v1/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func (a ActionType) String() string {
// Priority returns plan priority
func (a ActionType) Priority() ActionPriority {
switch a {
case ActionTypeMemberPhaseUpdate, ActionTypeMemberRIDUpdate:
return ActionPriorityHigh
default:
return ActionPriorityNormal
}
Expand Down Expand Up @@ -153,6 +155,10 @@ const (
ActionTypeBootstrapUpdate ActionType = "BootstrapUpdate"
// ActionTypeBootstrapSetPassword set password to the bootstrapped user
ActionTypeBootstrapSetPassword ActionType = "BootstrapSetPassword"
// ActionTypeMemberPhaseUpdate updated member phase. High priority
ActionTypeMemberPhaseUpdate ActionType = "MemberPhaseUpdate"
// ActionTypeMemberRIDUpdate updated member Run ID (UID). High priority
ActionTypeMemberRIDUpdate ActionType = "MemberRIDUpdate"
)

const (
Expand Down
17 changes: 17 additions & 0 deletions pkg/apis/deployment/v2alpha1/member_phase.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type MemberPhase string
const (
// MemberPhaseNone indicates that the state is not set yet
MemberPhaseNone MemberPhase = ""
// MemberPhasePending indicates that member propagation has been started
MemberPhasePending MemberPhase = "Pending"
// MemberPhaseCreated indicates that all resources needed for the member have been created
MemberPhaseCreated MemberPhase = "Created"
// MemberPhaseFailed indicates that the member is gone beyond hope of recovery. It must be replaced with a new member.
Expand All @@ -48,6 +50,11 @@ const (
MemberPhaseUpgrading MemberPhase = "Upgrading"
)

// IsPending returns true when given phase == "" OR "Pending"
func (p MemberPhase) IsPending() bool {
return p == MemberPhaseNone || p == MemberPhasePending
}

// IsFailed returns true when given phase == "Failed"
func (p MemberPhase) IsFailed() bool {
return p == MemberPhaseFailed
Expand All @@ -62,3 +69,13 @@ func (p MemberPhase) IsCreatedOrDrain() bool {
func (p MemberPhase) String() string {
return string(p)
}

// GetPhase parses string into phase
func GetPhase(phase string) (MemberPhase, bool) {
switch p := MemberPhase(phase); p {
case MemberPhaseNone, MemberPhasePending, MemberPhaseCreated, MemberPhaseFailed, MemberPhaseCleanOut, MemberPhaseDrain, MemberPhaseResign, MemberPhaseShuttingDown, MemberPhaseRotating, MemberPhaseRotateStart, MemberPhaseUpgrading:
return p, true
default:
return "", false
}
}
4 changes: 4 additions & 0 deletions pkg/apis/deployment/v2alpha1/member_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type MemberStatus struct {
// ID holds the unique ID of the member.
// This id is also used within the ArangoDB cluster to identify this server.
ID string `json:"id"`
// RID holds the ID of the member run.
// Value is updated in Pending Phase.
RID types.UID `json:"rid,omitempty"`
// Phase holds the current lifetime phase of this member
Phase MemberPhase `json:"phase"`
// CreatedAt holds the creation timestamp of this member.
Expand Down Expand Up @@ -82,6 +85,7 @@ type MemberStatus struct {
// Equal checks for equality
func (s MemberStatus) Equal(other MemberStatus) bool {
return s.ID == other.ID &&
s.RID == other.RID &&
s.Phase == other.Phase &&
util.TimeCompareEqual(s.CreatedAt, other.CreatedAt) &&
s.PersistentVolumeClaimName == other.PersistentVolumeClaimName &&
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/deployment/v2alpha1/member_status_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (l MemberStatusList) SelectMemberToRemove() (MemberStatus, error) {
}
// Try to find a not ready member
for _, m := range l {
if m.Phase == MemberPhaseNone {
if m.Phase.IsPending() {
return m, nil
}
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/deployment/v2alpha1/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func (a ActionType) String() string {
// Priority returns plan priority
func (a ActionType) Priority() ActionPriority {
switch a {
case ActionTypeMemberPhaseUpdate, ActionTypeMemberRIDUpdate:
return ActionPriorityHigh
default:
return ActionPriorityNormal
}
Expand Down Expand Up @@ -153,6 +155,10 @@ const (
ActionTypeBootstrapUpdate ActionType = "BootstrapUpdate"
// ActionTypeBootstrapSetPassword set password to the bootstrapped user
ActionTypeBootstrapSetPassword ActionType = "BootstrapSetPassword"
// ActionTypeMemberPhaseUpdate updated member phase. High priority
ActionTypeMemberPhaseUpdate ActionType = "MemberPhaseUpdate"
// ActionTypeMemberRIDUpdate updated member Run ID (UID). High priority
ActionTypeMemberRIDUpdate ActionType = "MemberRIDUpdate"
)

const (
Expand Down
12 changes: 12 additions & 0 deletions pkg/deployment/deployment_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ func runTestCase(t *testing.T, testCase testCaseStruct) {
if testCase.Resources != nil {
testCase.Resources(t, d)
}
// Set Pending phase
require.NoError(t, d.status.last.Members.ForeachServerGroup(func(group api.ServerGroup, list api.MemberStatusList) error {
for _, m := range list {
if m.Phase == api.MemberPhaseNone {
m.Phase = api.MemberPhasePending
if err := d.status.last.Members.Update(m, group); err != nil {
return err
}
}
}
return nil
}))

// Set members
require.NoError(t, d.status.last.Members.ForeachServerGroup(func(group api.ServerGroup, list api.MemberStatusList) error {
Expand Down
85 changes: 85 additions & 0 deletions pkg/deployment/reconcile/action_member_phase_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// DISCLAIMER
//
// Copyright 2020-2021 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
//
// Author Adam Janikowski
//

package reconcile

import (
"context"

api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/rs/zerolog"
)

func init() {
registerAction(api.ActionTypeMemberPhaseUpdate, newMemberPhaseUpdate)
}

const (
ActionTypeMemberPhaseUpdatePhaseKey string = "phase"
)

func newMemberPhaseUpdate(log zerolog.Logger, action api.Action, actionCtx ActionContext) Action {
a := &memberPhaseUpdateAction{}

a.actionImpl = newActionImplDefRef(log, action, actionCtx, defaultTimeout)

return a
}

type memberPhaseUpdateAction struct {
actionImpl

actionEmptyCheckProgress
}

func (a *memberPhaseUpdateAction) Start(ctx context.Context) (bool, error) {
log := a.log
m, ok := a.actionCtx.GetMemberStatusByID(a.action.MemberID)
if !ok {
log.Error().Msg("No such member")
return true, nil
}

phaseString, ok := a.action.Params[ActionTypeMemberPhaseUpdatePhaseKey]
if !ok {
log.Error().Msg("Phase not defined")
return true, nil
}

phase, ok := api.GetPhase(phaseString)
if !ok {
log.Error().Msgf("Phase %s unknown", phase)
return true, nil
}

if m.Phase == phase {
return true, nil
}

m.Phase = phase
if err := a.actionCtx.UpdateMember(ctx, m); err != nil {
return false, errors.WithStack(err)
}

return true, nil
}
68 changes: 68 additions & 0 deletions pkg/deployment/reconcile/action_member_rid_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// DISCLAIMER
//
// Copyright 2020-2021 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
//
// Author Adam Janikowski
//

package reconcile

import (
"context"

"k8s.io/apimachinery/pkg/util/uuid"

api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/rs/zerolog"
)

func init() {
registerAction(api.ActionTypeMemberRIDUpdate, newMemberRIDUpdate)
}

func newMemberRIDUpdate(log zerolog.Logger, action api.Action, actionCtx ActionContext) Action {
a := &memberRIDUpdateAction{}

a.actionImpl = newActionImplDefRef(log, action, actionCtx, defaultTimeout)

return a
}

type memberRIDUpdateAction struct {
actionImpl

actionEmptyCheckProgress
}

func (a *memberRIDUpdateAction) Start(ctx context.Context) (bool, error) {
log := a.log
m, ok := a.actionCtx.GetMemberStatusByID(a.action.MemberID)
if !ok {
log.Error().Msg("No such member")
return true, nil
}

m.RID = uuid.NewUUID()

if err := a.actionCtx.UpdateMember(ctx, m); err != nil {
return false, errors.WithStack(err)
}

return true, nil
}
Loading