Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow changing server group storage class. #183

Merged
merged 6 commits into from
Jun 18, 2018
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
6 changes: 6 additions & 0 deletions pkg/apis/deployment/v1alpha/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ const (
ActionTypeRenewTLSCACertificate ActionType = "RenewTLSCACertificate"
)

const (
// MemberIDPreviousAction is used for Action.MemberID when the MemberID
// should be derived from the previous action.
MemberIDPreviousAction = "@previous"
)

// Action represents a single action to be taken to update a deployment.
type Action struct {
// ID of this action (unique for every action)
Expand Down
4 changes: 0 additions & 4 deletions pkg/apis/deployment/v1alpha/server_group_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,5 @@ func (s ServerGroupSpec) ResetImmutableFields(group ServerGroup, fieldPrefix str
resetFields = append(resetFields, fieldPrefix+".count")
}
}
if s.GetStorageClassName() != target.GetStorageClassName() {
target.StorageClassName = util.NewStringOrNil(s.StorageClassName)
resetFields = append(resetFields, fieldPrefix+".storageClassName")
}
return resetFields
}
19 changes: 15 additions & 4 deletions pkg/deployment/context_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/arangodb/arangosync/tasks"
driver "github.com/arangodb/go-driver"
"github.com/arangodb/go-driver/agency"
"github.com/rs/zerolog/log"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -191,23 +192,23 @@ func (d *Deployment) GetSyncServerClient(ctx context.Context, group api.ServerGr

// CreateMember adds a new member to the given group.
// If ID is non-empty, it will be used, otherwise a new ID is created.
func (d *Deployment) CreateMember(group api.ServerGroup, id string) error {
func (d *Deployment) CreateMember(group api.ServerGroup, id string) (string, error) {
log := d.deps.Log
status, lastVersion := d.GetStatus()
id, err := createMember(log, &status, group, id, d.apiObject)
if err != nil {
log.Debug().Err(err).Str("group", group.AsRole()).Msg("Failed to create member")
return maskAny(err)
return "", maskAny(err)
}
// Save added member
if err := d.UpdateStatus(status, lastVersion); err != nil {
log.Debug().Err(err).Msg("Updating CR status failed")
return maskAny(err)
return "", maskAny(err)
}
// Create event about it
d.CreateEvent(k8sutil.NewMemberAddEvent(id, group.AsRole(), d.apiObject))

return nil
return id, nil
}

// DeletePod deletes a pod with given name in the namespace
Expand Down Expand Up @@ -304,6 +305,16 @@ func (d *Deployment) GetOwnedPVCs() ([]v1.PersistentVolumeClaim, error) {
return myPVCs, nil
}

// GetPvc gets a PVC by the given name, in the samespace of the deployment.
func (d *Deployment) GetPvc(pvcName string) (*v1.PersistentVolumeClaim, error) {
pvc, err := d.deps.KubeCli.CoreV1().PersistentVolumeClaims(d.apiObject.GetNamespace()).Get(pvcName, metav1.GetOptions{})
if err != nil {
log.Debug().Err(err).Str("pvc-name", pvcName).Msg("Failed to get PVC")
return nil, maskAny(err)
}
return pvc, nil
}

// GetTLSKeyfile returns the keyfile encoded TLS certificate+key for
// the given member.
func (d *Deployment) GetTLSKeyfile(group api.ServerGroup, member api.MemberStatus) (string, error) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/deployment/reconcile/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ type Action interface {
CheckProgress(ctx context.Context) (bool, bool, error)
// Timeout returns the amount of time after which this action will timeout.
Timeout() time.Duration
// Return the MemberID used / created in this action
MemberID() string
}
16 changes: 12 additions & 4 deletions pkg/deployment/reconcile/action_add_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,22 @@ func NewAddMemberAction(log zerolog.Logger, action api.Action, actionCtx ActionC

// actionAddMember implements an AddMemberAction.
type actionAddMember struct {
log zerolog.Logger
action api.Action
actionCtx ActionContext
log zerolog.Logger
action api.Action
actionCtx ActionContext
newMemberID string
}

// Start performs the start of the action.
// Returns true if the action is completely finished, false in case
// the start time needs to be recorded and a ready condition needs to be checked.
func (a *actionAddMember) Start(ctx context.Context) (bool, error) {
if err := a.actionCtx.CreateMember(a.action.Group, a.action.MemberID); err != nil {
newID, err := a.actionCtx.CreateMember(a.action.Group, a.action.MemberID)
if err != nil {
log.Debug().Err(err).Msg("Failed to create member")
return false, maskAny(err)
}
a.newMemberID = newID
return true, nil
}

Expand All @@ -70,3 +73,8 @@ func (a *actionAddMember) CheckProgress(ctx context.Context) (bool, bool, error)
func (a *actionAddMember) Timeout() time.Duration {
return addMemberTimeout
}

// Return the MemberID used / created in this action
func (a *actionAddMember) MemberID() string {
return a.newMemberID
}
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_cleanout_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,8 @@ func (a *actionCleanoutMember) CheckProgress(ctx context.Context) (bool, bool, e
func (a *actionCleanoutMember) Timeout() time.Duration {
return cleanoutMemberTimeout
}

// Return the MemberID used / created in this action
func (a *actionCleanoutMember) MemberID() string {
return a.action.MemberID
}
11 changes: 6 additions & 5 deletions pkg/deployment/reconcile/action_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type ActionContext interface {
GetMemberStatusByID(id string) (api.MemberStatus, bool)
// CreateMember adds a new member to the given group.
// If ID is non-empty, it will be used, otherwise a new ID is created.
CreateMember(group api.ServerGroup, id string) error
CreateMember(group api.ServerGroup, id string) (string, error)
// UpdateMember updates the deployment status wrt the given member.
UpdateMember(member api.MemberStatus) error
// RemoveMemberByID removes a member with given id.
Expand Down Expand Up @@ -157,11 +157,12 @@ func (ac *actionContext) GetMemberStatusByID(id string) (api.MemberStatus, bool)

// CreateMember adds a new member to the given group.
// If ID is non-empty, it will be used, otherwise a new ID is created.
func (ac *actionContext) CreateMember(group api.ServerGroup, id string) error {
if err := ac.context.CreateMember(group, id); err != nil {
return maskAny(err)
func (ac *actionContext) CreateMember(group api.ServerGroup, id string) (string, error) {
result, err := ac.context.CreateMember(group, id)
if err != nil {
return "", maskAny(err)
}
return nil
return result, nil
}

// UpdateMember updates the deployment status wrt the given member.
Expand Down
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_remove_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,8 @@ func (a *actionRemoveMember) CheckProgress(ctx context.Context) (bool, bool, err
func (a *actionRemoveMember) Timeout() time.Duration {
return removeMemberTimeout
}

// Return the MemberID used / created in this action
func (a *actionRemoveMember) MemberID() string {
return a.action.MemberID
}
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_renew_tls_ca_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ func (a *renewTLSCACertificateAction) CheckProgress(ctx context.Context) (bool,
func (a *renewTLSCACertificateAction) Timeout() time.Duration {
return renewTLSCACertificateTimeout
}

// Return the MemberID used / created in this action
func (a *renewTLSCACertificateAction) MemberID() string {
return a.action.MemberID
}
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_renew_tls_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,8 @@ func (a *renewTLSCertificateAction) CheckProgress(ctx context.Context) (bool, bo
func (a *renewTLSCertificateAction) Timeout() time.Duration {
return renewTLSCertificateTimeout
}

// Return the MemberID used / created in this action
func (a *renewTLSCertificateAction) MemberID() string {
return a.action.MemberID
}
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_rotate_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,8 @@ func (a *actionRotateMember) CheckProgress(ctx context.Context) (bool, bool, err
func (a *actionRotateMember) Timeout() time.Duration {
return rotateMemberTimeout
}

// Return the MemberID used / created in this action
func (a *actionRotateMember) MemberID() string {
return a.action.MemberID
}
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_shutdown_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,8 @@ func (a *actionShutdownMember) CheckProgress(ctx context.Context) (bool, bool, e
func (a *actionShutdownMember) Timeout() time.Duration {
return shutdownMemberTimeout
}

// Return the MemberID used / created in this action
func (a *actionShutdownMember) MemberID() string {
return a.action.MemberID
}
5 changes: 5 additions & 0 deletions pkg/deployment/reconcile/action_upgrade_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,8 @@ func (a *actionUpgradeMember) CheckProgress(ctx context.Context) (bool, bool, er
func (a *actionUpgradeMember) Timeout() time.Duration {
return upgradeMemberTimeout
}

// Return the MemberID used / created in this action
func (a *actionUpgradeMember) MemberID() string {
return a.action.MemberID
}
27 changes: 26 additions & 1 deletion pkg/deployment/reconcile/action_wait_for_member_up.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (a *actionWaitForMemberUp) CheckProgress(ctx context.Context) (bool, bool,
if a.action.Group == api.ServerGroupAgents {
return a.checkProgressAgent(ctx)
}
return a.checkProgressSingle(ctx)
return a.checkProgressSingleInActiveFailover(ctx)
default:
if a.action.Group == api.ServerGroupAgents {
return a.checkProgressAgent(ctx)
Expand All @@ -99,6 +99,26 @@ func (a *actionWaitForMemberUp) checkProgressSingle(ctx context.Context) (bool,
return true, false, nil
}

// checkProgressSingleInActiveFailover checks the progress of the action in the case
// of a single server as part of an active failover deployment.
func (a *actionWaitForMemberUp) checkProgressSingleInActiveFailover(ctx context.Context) (bool, bool, error) {
log := a.log
c, err := a.actionCtx.GetDatabaseClient(ctx)
if err != nil {
log.Debug().Err(err).Msg("Failed to create database client")
return false, false, maskAny(err)
}
if _, err := c.Version(ctx); err != nil {
log.Debug().Err(err).Msg("Failed to get version")
return false, false, maskAny(err)
}
if _, err := c.Databases(ctx); err != nil {
log.Debug().Err(err).Msg("Failed to get databases")
return false, false, maskAny(err)
}
return true, false, nil
}

// checkProgressAgent checks the progress of the action in the case
// of an agent.
func (a *actionWaitForMemberUp) checkProgressAgent(ctx context.Context) (bool, bool, error) {
Expand Down Expand Up @@ -170,3 +190,8 @@ func (a *actionWaitForMemberUp) checkProgressArangoSync(ctx context.Context) (bo
func (a *actionWaitForMemberUp) Timeout() time.Duration {
return waitForMemberUpTimeout
}

// Return the MemberID used / created in this action
func (a *actionWaitForMemberUp) MemberID() string {
return a.action.MemberID
}
5 changes: 4 additions & 1 deletion pkg/deployment/reconcile/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ type Context interface {
CreateEvent(evt *v1.Event)
// CreateMember adds a new member to the given group.
// If ID is non-empty, it will be used, otherwise a new ID is created.
CreateMember(group api.ServerGroup, id string) error
// Returns ID, error
CreateMember(group api.ServerGroup, id string) (string, error)
// DeletePod deletes a pod with given name in the namespace
// of the deployment. If the pod does not exist, the error is ignored.
DeletePod(podName string) error
Expand All @@ -74,6 +75,8 @@ type Context interface {
RemovePodFinalizers(podName string) error
// GetOwnedPods returns a list of all pods owned by the deployment.
GetOwnedPods() ([]v1.Pod, error)
// GetPvc gets a PVC by the given name, in the samespace of the deployment.
GetPvc(pvcName string) (*v1.PersistentVolumeClaim, error)
// GetTLSKeyfile returns the keyfile encoded TLS certificate+key for
// the given member.
GetTLSKeyfile(group api.ServerGroup, member api.MemberStatus) (string, error)
Expand Down
21 changes: 14 additions & 7 deletions pkg/deployment/reconcile/plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (d *Reconciler) CreatePlan() error {
apiObject := d.context.GetAPIObject()
spec := d.context.GetSpec()
status, lastVersion := d.context.GetStatus()
newPlan, changed := createPlan(d.log, apiObject, status.Plan, spec, status, pods, d.context.GetTLSKeyfile, d.context.GetTLSCA)
newPlan, changed := createPlan(d.log, apiObject, status.Plan, spec, status, pods, d.context.GetTLSKeyfile, d.context.GetTLSCA, d.context.GetPvc, d.context.CreateEvent)

// If not change, we're done
if !changed {
Expand All @@ -76,11 +76,13 @@ func (d *Reconciler) CreatePlan() error {
// createPlan considers the given specification & status and creates a plan to get the status in line with the specification.
// If a plan already exists, the given plan is returned with false.
// Otherwise the new plan is returned with a boolean true.
func createPlan(log zerolog.Logger, apiObject metav1.Object,
func createPlan(log zerolog.Logger, apiObject k8sutil.APIObject,
currentPlan api.Plan, spec api.DeploymentSpec,
status api.DeploymentStatus, pods []v1.Pod,
getTLSKeyfile func(group api.ServerGroup, member api.MemberStatus) (string, error),
getTLSCA func(string) (string, string, bool, error)) (api.Plan, bool) {
getTLSCA func(string) (string, string, bool, error),
getPVC func(pvcName string) (*v1.PersistentVolumeClaim, error),
createEvent func(evt *v1.Event)) (api.Plan, bool) {
if len(currentPlan) > 0 {
// Plan already exists, complete that first
return currentPlan, false
Expand Down Expand Up @@ -175,14 +177,19 @@ func createPlan(log zerolog.Logger, apiObject metav1.Object,
})
}

// Check for the need to rotate TLS CA certificate and all members
// Check for the need to rotate TLS certificate of a members
if len(plan) == 0 {
plan = createRotateTLSCAPlan(log, spec, status, getTLSCA)
plan = createRotateTLSServerCertificatePlan(log, spec, status, getTLSKeyfile)
}

// Check for the need to rotate TLS certificate of a members
// Check for changes storage classes or requirements
if len(plan) == 0 {
plan = createRotateTLSServerCertificatePlan(log, spec, status, getTLSKeyfile)
plan = createRotateServerStoragePlan(log, apiObject, spec, status, getPVC, createEvent)
}

// Check for the need to rotate TLS CA certificate and all members
if len(plan) == 0 {
plan = createRotateTLSCAPlan(log, spec, status, getTLSCA)
}

// Return plan
Expand Down
Loading