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

Rotation support for members. #49

Merged
merged 22 commits into from
Mar 23, 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
9 changes: 8 additions & 1 deletion deps/github.com/arangodb/go-driver/http/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ type ConnectionConfig struct {
// directly after use, resulting in a large number of connections in `TIME_WAIT` state.
// When this value is not set, the driver will set it to 64 automatically.
Transport http.RoundTripper
// DontFollowRedirect; if set, redirect will not be followed, response from the initial request will be returned without an error
// DontFollowRedirect takes precendance over FailOnRedirect.
DontFollowRedirect bool
// FailOnRedirect; if set, redirect will not be followed, instead the status code is returned as error
FailOnRedirect bool
// Cluster configuration settings
Expand Down Expand Up @@ -137,7 +140,11 @@ func newHTTPConnection(endpoint string, config ConnectionConfig) (driver.Connect
httpClient := &http.Client{
Transport: config.Transport,
}
if config.FailOnRedirect {
if config.DontFollowRedirect {
httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // Do not wrap, standard library will not understand
}
} else if config.FailOnRedirect {
httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return driver.ArangoError{
HasError: true,
Expand Down
1 change: 1 addition & 0 deletions examples/nodeport-cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ spec:
app: arangodb
role: coordinator
type: NodePort
publishNotReadyAddresses: true
ports:
- protocol: TCP
port: 8529
Expand Down
6 changes: 6 additions & 0 deletions examples/simple-cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ metadata:
name: "example-simple-cluster"
spec:
mode: cluster
image: arangodb/arangodb:3.3.4
tls:
altNames: ["kube-01", "kube-02", "kube-03"]
coordinators:
args:
- --log.level=true
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper
CreateCRD: operatorOptions.createCRD,
}
deps := operator.Dependencies{
Log: logService.MustGetLogger("operator"),
LogService: logService,
KubeCli: kubecli,
KubeExtCli: kubeExtCli,
CRCli: crCli,
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/deployment/v1alpha/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const (
ConditionTypeReady ConditionType = "Ready"
// ConditionTypeTerminated indicates that the member has terminated and will not restart.
ConditionTypeTerminated ConditionType = "Terminated"
// ConditionTypeAutoUpgrade indicates that the member has to be started with `--database.auto-upgrade` once.
ConditionTypeAutoUpgrade ConditionType = "AutoUpgrade"
)

// Condition represents one current condition of a deployment or deployment member.
Expand Down
21 changes: 21 additions & 0 deletions pkg/apis/deployment/v1alpha/deployment_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@ func (s DeploymentSpec) IsSecure() bool {
return s.TLS.IsSecure()
}

// GetServerGroupSpec returns the server group spec (from this
// deployment spec) for the given group.
func (s DeploymentSpec) GetServerGroupSpec(group ServerGroup) ServerGroupSpec {
switch group {
case ServerGroupSingle:
return s.Single
case ServerGroupAgents:
return s.Agents
case ServerGroupDBServers:
return s.DBServers
case ServerGroupCoordinators:
return s.Coordinators
case ServerGroupSyncMasters:
return s.SyncMasters
case ServerGroupSyncWorkers:
return s.SyncWorkers
default:
return ServerGroupSpec{}
}
}

// SetDefaults fills in default values when a field is not specified.
func (s *DeploymentSpec) SetDefaults(deploymentName string) {
if s.Mode == "" {
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/deployment/v1alpha/member_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ const (
MemberStateCleanOut MemberState = "CleanOut"
// MemberStateShuttingDown indicates that a member is shutting down
MemberStateShuttingDown MemberState = "ShuttingDown"
// MemberStateRotating indicates that a member is being rotated
MemberStateRotating MemberState = "Rotating"
// MemberStateUpgrading indicates that a member is in the process of upgrading its database data format
MemberStateUpgrading MemberState = "Upgrading"
)
32 changes: 31 additions & 1 deletion pkg/apis/deployment/v1alpha/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@

package v1alpha

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
import (
"github.com/dchest/uniuri"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ActionType is a strongly typed name for a plan action item
type ActionType string
Expand All @@ -36,18 +39,45 @@ const (
ActionTypeCleanOutMember ActionType = "CleanOutMember"
// ActionTypeShutdownMember causes a member to be shutdown and removed from the cluster.
ActionTypeShutdownMember ActionType = "ShutdownMember"
// ActionTypeRotateMember causes a member to be shutdown and have it's pod removed.
ActionTypeRotateMember ActionType = "RotateMember"
// 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"
)

// 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"`
// 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 metav1.Time `json:"creationTime"`
// StartTime is set the when the action has been started, but needs to wait to be finished.
StartTime *metav1.Time `json:"startTime,omitempty"`
// Reason for this action
Reason string `json:"reason,omitempty"`
}

// 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: metav1.Now(),
}
if len(reason) != 0 {
a.Reason = reason[0]
}
return a
}

// Plan is a list of actions that will be taken to update a deployment.
Expand Down
20 changes: 20 additions & 0 deletions pkg/apis/deployment/v1alpha/server_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,26 @@ func (g ServerGroup) AsRole() string {
}
}

// AsRoleAbbreviated returns the abbreviation of the "role" value for the given group.
func (g ServerGroup) AsRoleAbbreviated() string {
switch g {
case ServerGroupSingle:
return "sngl"
case ServerGroupAgents:
return "agnt"
case ServerGroupDBServers:
return "prmr"
case ServerGroupCoordinators:
return "crdn"
case ServerGroupSyncMasters:
return "syma"
case ServerGroupSyncWorkers:
return "sywo"
default:
return "?"
}
}

// IsArangod returns true when the groups runs servers of type `arangod`.
func (g ServerGroup) IsArangod() bool {
switch g {
Expand Down
9 changes: 9 additions & 0 deletions pkg/apis/deployment/v1alpha/server_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ func TestServerGroupAsRole(t *testing.T) {
assert.Equal(t, "syncworker", ServerGroupSyncWorkers.AsRole())
}

func TestServerGroupAsRoleAbbreviated(t *testing.T) {
assert.Equal(t, "sngl", ServerGroupSingle.AsRoleAbbreviated())
assert.Equal(t, "agnt", ServerGroupAgents.AsRoleAbbreviated())
assert.Equal(t, "prmr", ServerGroupDBServers.AsRoleAbbreviated())
assert.Equal(t, "crdn", ServerGroupCoordinators.AsRoleAbbreviated())
assert.Equal(t, "syma", ServerGroupSyncMasters.AsRoleAbbreviated())
assert.Equal(t, "sywo", ServerGroupSyncWorkers.AsRoleAbbreviated())
}

func TestServerGroupIsArangod(t *testing.T) {
assert.True(t, ServerGroupSingle.IsArangod())
assert.True(t, ServerGroupAgents.IsArangod())
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/deployment/v1alpha/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Action) DeepCopyInto(out *Action) {
*out = *in
in.CreationTime.DeepCopyInto(&out.CreationTime)
if in.StartTime != nil {
in, out := &in.StartTime, &out.StartTime
if *in == nil {
Expand Down
38 changes: 38 additions & 0 deletions pkg/deployment/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// DISCLAIMER
//
// Copyright 2018 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 Ewout Prangsma
//

package deployment

import (
"context"
)

// Action executes a single Plan item.
type Action interface {
// 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.
Start(ctx context.Context) (bool, error)
// CheckProgress checks the progress of the action.
// Returns true if the action is completely finished, false otherwise.
CheckProgress(ctx context.Context) (bool, error)
}
66 changes: 66 additions & 0 deletions pkg/deployment/action_add_member.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// DISCLAIMER
//
// Copyright 2018 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 Ewout Prangsma
//

package deployment

import (
"context"

api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)

// NewAddMemberAction creates a new Action that implements the given
// planned AddMember action.
func NewAddMemberAction(log zerolog.Logger, action api.Action, actionCtx ActionContext) Action {
return &actionAddMember{
log: log,
action: action,
actionCtx: actionCtx,
}
}

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

// 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); err != nil {
log.Debug().Err(err).Msg("Failed to create member")
return false, maskAny(err)
}
return true, nil
}

// CheckProgress checks the progress of the action.
// Returns true if the action is completely finished, false otherwise.
func (a *actionAddMember) CheckProgress(ctx context.Context) (bool, error) {
// Nothing todo
return true, nil
}
Loading