mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] [EE] Ordered Member IDs (#1066)
This commit is contained in:
parent
96d9faddea
commit
f8fb748464
13 changed files with 217 additions and 29 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
|
||||
- (Feature) Add ArangoDeployment ServerGroupStatus
|
||||
- (Feature) (EE) Ordered Member IDs
|
||||
|
||||
## [1.2.15](https://github.com/arangodb/kube-arangodb/tree/1.2.15) (2022-07-20)
|
||||
- (Bugfix) Ensure pod names not too long
|
||||
|
|
68
pkg/apis/deployment/v1/server_group_index_method.go
Normal file
68
pkg/apis/deployment/v1/server_group_index_method.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// 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 v1
|
||||
|
||||
import "github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
|
||||
type ServerGroupIndexMethod string
|
||||
|
||||
const (
|
||||
DefaultServerGroupIndexMethod = ServerGroupIndexMethodRandom
|
||||
ServerGroupIndexMethodRandom ServerGroupIndexMethod = "random"
|
||||
ServerGroupIndexMethodOrdered ServerGroupIndexMethod = "ordered"
|
||||
)
|
||||
|
||||
func (s *ServerGroupIndexMethod) Equal(b *ServerGroupIndexMethod) bool {
|
||||
if s == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if s == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return *s == *b
|
||||
}
|
||||
|
||||
func (s *ServerGroupIndexMethod) Validate() error {
|
||||
switch v := s.Get(); v {
|
||||
case ServerGroupIndexMethodRandom, ServerGroupIndexMethodOrdered:
|
||||
return nil
|
||||
default:
|
||||
return errors.Newf("Unknown IndexMethod %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s ServerGroupIndexMethod) New() *ServerGroupIndexMethod {
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *ServerGroupIndexMethod) Get() ServerGroupIndexMethod {
|
||||
if s != nil {
|
||||
switch *s {
|
||||
case ServerGroupIndexMethodRandom:
|
||||
return ServerGroupIndexMethodRandom
|
||||
case ServerGroupIndexMethodOrdered:
|
||||
return ServerGroupIndexMethodOrdered
|
||||
}
|
||||
}
|
||||
return DefaultServerGroupIndexMethod
|
||||
}
|
|
@ -153,6 +153,8 @@ type ServerGroupSpec struct {
|
|||
AllowMemberRecreation *bool `json:"allowMemberRecreation,omitempty"`
|
||||
// TerminationGracePeriodSeconds override default TerminationGracePeriodSeconds for pods - via silent rotation
|
||||
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
||||
// IndexMethod define group Indexing method
|
||||
IndexMethod *ServerGroupIndexMethod `json:"indexMethod,omitempty"`
|
||||
}
|
||||
|
||||
// ServerGroupSpecSecurityContext contains specification for pod security context
|
||||
|
@ -539,6 +541,7 @@ func (s *ServerGroupSpec) validate() error {
|
|||
shared.PrefixResourceError("volumes", s.Volumes.Validate()),
|
||||
shared.PrefixResourceError("volumeMounts", s.VolumeMounts.Validate()),
|
||||
shared.PrefixResourceError("initContainers", s.InitContainers.Validate()),
|
||||
shared.PrefixResourceError("IndexMethod", s.IndexMethod.Validate()),
|
||||
s.validateVolumes(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
|
||||
package v1
|
||||
|
||||
import "github.com/arangodb/kube-arangodb/pkg/util"
|
||||
|
||||
type ServerGroupStatus struct {
|
||||
Index *int `json:"index,omitempty"`
|
||||
}
|
||||
|
||||
func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
|
||||
|
@ -32,5 +35,5 @@ func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return util.CompareIntp(s.Index, b.Index)
|
||||
}
|
||||
|
|
22
pkg/apis/deployment/v1/zz_generated.deepcopy.go
generated
22
pkg/apis/deployment/v1/zz_generated.deepcopy.go
generated
|
@ -1186,32 +1186,32 @@ func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) {
|
|||
if in.Single != nil {
|
||||
in, out := &in.Single, &out.Single
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Agents != nil {
|
||||
in, out := &in.Agents, &out.Agents
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.DBServers != nil {
|
||||
in, out := &in.DBServers, &out.DBServers
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Coordinators != nil {
|
||||
in, out := &in.Coordinators, &out.Coordinators
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.SyncMasters != nil {
|
||||
in, out := &in.SyncMasters, &out.SyncMasters
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.SyncWorkers != nil {
|
||||
in, out := &in.SyncWorkers, &out.SyncWorkers
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -2368,6 +2368,11 @@ func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) {
|
|||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.IndexMethod != nil {
|
||||
in, out := &in.IndexMethod, &out.IndexMethod
|
||||
*out = new(ServerGroupIndexMethod)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -2681,6 +2686,11 @@ func (in ServerGroupSpecVolumes) DeepCopy() ServerGroupSpecVolumes {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) {
|
||||
*out = *in
|
||||
if in.Index != nil {
|
||||
in, out := &in.Index, &out.Index
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
68
pkg/apis/deployment/v2alpha1/server_group_index_method.go
Normal file
68
pkg/apis/deployment/v2alpha1/server_group_index_method.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// 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/arangodb/kube-arangodb/pkg/util/errors"
|
||||
|
||||
type ServerGroupIndexMethod string
|
||||
|
||||
const (
|
||||
DefaultServerGroupIndexMethod = ServerGroupIndexMethodRandom
|
||||
ServerGroupIndexMethodRandom ServerGroupIndexMethod = "random"
|
||||
ServerGroupIndexMethodOrdered ServerGroupIndexMethod = "ordered"
|
||||
)
|
||||
|
||||
func (s *ServerGroupIndexMethod) Equal(b *ServerGroupIndexMethod) bool {
|
||||
if s == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if s == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return *s == *b
|
||||
}
|
||||
|
||||
func (s *ServerGroupIndexMethod) Validate() error {
|
||||
switch v := s.Get(); v {
|
||||
case ServerGroupIndexMethodRandom, ServerGroupIndexMethodOrdered:
|
||||
return nil
|
||||
default:
|
||||
return errors.Newf("Unknown IndexMethod %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s ServerGroupIndexMethod) New() *ServerGroupIndexMethod {
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *ServerGroupIndexMethod) Get() ServerGroupIndexMethod {
|
||||
if s != nil {
|
||||
switch *s {
|
||||
case ServerGroupIndexMethodRandom:
|
||||
return ServerGroupIndexMethodRandom
|
||||
case ServerGroupIndexMethodOrdered:
|
||||
return ServerGroupIndexMethodOrdered
|
||||
}
|
||||
}
|
||||
return DefaultServerGroupIndexMethod
|
||||
}
|
|
@ -153,6 +153,8 @@ type ServerGroupSpec struct {
|
|||
AllowMemberRecreation *bool `json:"allowMemberRecreation,omitempty"`
|
||||
// TerminationGracePeriodSeconds override default TerminationGracePeriodSeconds for pods - via silent rotation
|
||||
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
||||
// IndexMethod define group Indexing method
|
||||
IndexMethod *ServerGroupIndexMethod `json:"indexMethod,omitempty"`
|
||||
}
|
||||
|
||||
// ServerGroupSpecSecurityContext contains specification for pod security context
|
||||
|
@ -539,6 +541,7 @@ func (s *ServerGroupSpec) validate() error {
|
|||
shared.PrefixResourceError("volumes", s.Volumes.Validate()),
|
||||
shared.PrefixResourceError("volumeMounts", s.VolumeMounts.Validate()),
|
||||
shared.PrefixResourceError("initContainers", s.InitContainers.Validate()),
|
||||
shared.PrefixResourceError("IndexMethod", s.IndexMethod.Validate()),
|
||||
s.validateVolumes(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
|
||||
package v2alpha1
|
||||
|
||||
import "github.com/arangodb/kube-arangodb/pkg/util"
|
||||
|
||||
type ServerGroupStatus struct {
|
||||
Index *int `json:"index,omitempty"`
|
||||
}
|
||||
|
||||
func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
|
||||
|
@ -32,5 +35,5 @@ func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return util.CompareIntp(s.Index, b.Index)
|
||||
}
|
||||
|
|
|
@ -1186,32 +1186,32 @@ func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) {
|
|||
if in.Single != nil {
|
||||
in, out := &in.Single, &out.Single
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Agents != nil {
|
||||
in, out := &in.Agents, &out.Agents
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.DBServers != nil {
|
||||
in, out := &in.DBServers, &out.DBServers
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Coordinators != nil {
|
||||
in, out := &in.Coordinators, &out.Coordinators
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.SyncMasters != nil {
|
||||
in, out := &in.SyncMasters, &out.SyncMasters
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.SyncWorkers != nil {
|
||||
in, out := &in.SyncWorkers, &out.SyncWorkers
|
||||
*out = new(ServerGroupStatus)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -2368,6 +2368,11 @@ func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) {
|
|||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.IndexMethod != nil {
|
||||
in, out := &in.IndexMethod, &out.IndexMethod
|
||||
*out = new(ServerGroupIndexMethod)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -2681,6 +2686,11 @@ func (in ServerGroupSpecVolumes) DeepCopy() ServerGroupSpecVolumes {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) {
|
||||
*out = *in
|
||||
if in.Index != nil {
|
||||
in, out := &in.Index, &out.Index
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ func (d *Deployment) GetSyncServerClient(ctx context.Context, group api.ServerGr
|
|||
// If ID is non-empty, it will be used, otherwise a new ID is created.
|
||||
func (d *Deployment) CreateMember(ctx context.Context, group api.ServerGroup, id string, mods ...reconcile.CreateMemberMod) (string, error) {
|
||||
if err := d.WithStatusUpdateErr(ctx, func(s *api.DeploymentStatus) (bool, error) {
|
||||
nid, err := d.createMember(s, group, id, d.apiObject, mods...)
|
||||
nid, err := d.createMember(d.GetSpec(), s, group, id, d.apiObject, mods...)
|
||||
if err != nil {
|
||||
d.log.Err(err).Str("group", group.AsRole()).Debug("Failed to create member")
|
||||
return false, errors.WithStack(err)
|
||||
|
|
|
@ -23,8 +23,19 @@ package deployment
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/names"
|
||||
)
|
||||
|
||||
func (d *Deployment) createInitialTopology(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployment) renderMemberID(_ api.DeploymentSpec, status *api.DeploymentStatus, _ *api.ServerGroupStatus, group api.ServerGroup) string {
|
||||
for {
|
||||
if id := names.GetArangodID(group); !status.Members.ContainsID(id) {
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,11 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/reconcile"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/names"
|
||||
)
|
||||
|
||||
func (d *Deployment) createAgencyMapping(ctx context.Context) error {
|
||||
spec := d.GetSpec()
|
||||
status, _ := d.GetStatus()
|
||||
status := d.GetStatusSnapshot()
|
||||
|
||||
if !spec.Mode.HasAgents() {
|
||||
return nil
|
||||
|
@ -65,12 +64,15 @@ func (d *Deployment) createAgencyMapping(ctx context.Context) error {
|
|||
i.IDs = append(i.IDs, agents[id].ID)
|
||||
}
|
||||
|
||||
agentsStatus := status.GetServerGroupStatus(api.ServerGroupAgents)
|
||||
|
||||
for len(i.IDs) < *spec.Agents.Count {
|
||||
i.IDs = append(i.IDs, names.GetArangodID(api.ServerGroupAgents))
|
||||
i.IDs = append(i.IDs, d.renderMemberID(spec, &status, &agentsStatus, api.ServerGroupAgents))
|
||||
}
|
||||
|
||||
return d.WithStatusUpdate(ctx, func(s *api.DeploymentStatus) bool {
|
||||
s.Agency = &i
|
||||
s.UpdateServerGroupStatus(api.ServerGroupAgents, agentsStatus)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
@ -78,8 +80,10 @@ func (d *Deployment) createAgencyMapping(ctx context.Context) error {
|
|||
// createMember creates member and adds it to the applicable member list.
|
||||
// Note: This does not create any pods of PVCs
|
||||
// Note: The updated status is not yet written to the apiserver.
|
||||
func (d *Deployment) createMember(status *api.DeploymentStatus, group api.ServerGroup, id string, apiObject *api.ArangoDeployment, mods ...reconcile.CreateMemberMod) (string, error) {
|
||||
m, err := d.renderMember(status, group, id, apiObject)
|
||||
func (d *Deployment) createMember(spec api.DeploymentSpec, status *api.DeploymentStatus, group api.ServerGroup, id string, apiObject *api.ArangoDeployment, mods ...reconcile.CreateMemberMod) (string, error) {
|
||||
gs := status.GetServerGroupStatus(group)
|
||||
|
||||
m, err := d.renderMember(spec, status, &gs, group, id, apiObject)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -94,10 +98,12 @@ func (d *Deployment) createMember(status *api.DeploymentStatus, group api.Server
|
|||
return "", err
|
||||
}
|
||||
|
||||
status.UpdateServerGroupStatus(group, gs)
|
||||
|
||||
return m.ID, nil
|
||||
}
|
||||
|
||||
func (d *Deployment) renderMember(status *api.DeploymentStatus, group api.ServerGroup, id string, apiObject *api.ArangoDeployment) (*api.MemberStatus, error) {
|
||||
func (d *Deployment) renderMember(spec api.DeploymentSpec, status *api.DeploymentStatus, groupStatus *api.ServerGroupStatus, group api.ServerGroup, id string, apiObject *api.ArangoDeployment) (*api.MemberStatus, error) {
|
||||
if group == api.ServerGroupAgents {
|
||||
if status.Agency == nil {
|
||||
return nil, errors.New("Agency is not yet defined")
|
||||
|
@ -113,13 +119,7 @@ func (d *Deployment) renderMember(status *api.DeploymentStatus, group api.Server
|
|||
}
|
||||
} else {
|
||||
if id == "" {
|
||||
for {
|
||||
id = names.GetArangodID(group)
|
||||
if !status.Members.ContainsID(id) {
|
||||
break
|
||||
}
|
||||
// Duplicate, try again
|
||||
}
|
||||
id = d.renderMemberID(spec, status, groupStatus, group)
|
||||
}
|
||||
}
|
||||
if id == "" {
|
||||
|
|
|
@ -30,7 +30,15 @@ import (
|
|||
)
|
||||
|
||||
func GetArangodID(group api.ServerGroup) string {
|
||||
return fmt.Sprintf("%s%s", GetArangodIDPrefix(group), strings.ToLower(uniuri.NewLen(8)))
|
||||
return GetArangodIDPredefined(group, strings.ToLower(uniuri.NewLen(8)))
|
||||
}
|
||||
|
||||
func GetArangodIDInt(group api.ServerGroup, id int) string {
|
||||
return fmt.Sprintf("%s%s", GetArangodIDPrefix(group), fmt.Sprintf("%08d", id))
|
||||
}
|
||||
|
||||
func GetArangodIDPredefined(group api.ServerGroup, id string) string {
|
||||
return fmt.Sprintf("%s%s", GetArangodIDPrefix(group), id)
|
||||
}
|
||||
|
||||
// GetArangodIDPrefix returns the prefix required ID's of arangod servers
|
||||
|
|
Loading…
Reference in a new issue