1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-15 17:51:03 +00:00

[Feature] [EE] Ordered Member IDs (#1066)

This commit is contained in:
Adam Janikowski 2022-07-22 09:32:24 +02:00 committed by GitHub
parent 96d9faddea
commit f8fb748464
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 217 additions and 29 deletions

View file

@ -2,6 +2,7 @@
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A) ## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- (Feature) Add ArangoDeployment ServerGroupStatus - (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) ## [1.2.15](https://github.com/arangodb/kube-arangodb/tree/1.2.15) (2022-07-20)
- (Bugfix) Ensure pod names not too long - (Bugfix) Ensure pod names not too long

View 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
}

View file

@ -153,6 +153,8 @@ type ServerGroupSpec struct {
AllowMemberRecreation *bool `json:"allowMemberRecreation,omitempty"` AllowMemberRecreation *bool `json:"allowMemberRecreation,omitempty"`
// TerminationGracePeriodSeconds override default TerminationGracePeriodSeconds for pods - via silent rotation // TerminationGracePeriodSeconds override default TerminationGracePeriodSeconds for pods - via silent rotation
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
// IndexMethod define group Indexing method
IndexMethod *ServerGroupIndexMethod `json:"indexMethod,omitempty"`
} }
// ServerGroupSpecSecurityContext contains specification for pod security context // ServerGroupSpecSecurityContext contains specification for pod security context
@ -539,6 +541,7 @@ func (s *ServerGroupSpec) validate() error {
shared.PrefixResourceError("volumes", s.Volumes.Validate()), shared.PrefixResourceError("volumes", s.Volumes.Validate()),
shared.PrefixResourceError("volumeMounts", s.VolumeMounts.Validate()), shared.PrefixResourceError("volumeMounts", s.VolumeMounts.Validate()),
shared.PrefixResourceError("initContainers", s.InitContainers.Validate()), shared.PrefixResourceError("initContainers", s.InitContainers.Validate()),
shared.PrefixResourceError("IndexMethod", s.IndexMethod.Validate()),
s.validateVolumes(), s.validateVolumes(),
) )
} }

View file

@ -20,7 +20,10 @@
package v1 package v1
import "github.com/arangodb/kube-arangodb/pkg/util"
type ServerGroupStatus struct { type ServerGroupStatus struct {
Index *int `json:"index,omitempty"`
} }
func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool { func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
@ -32,5 +35,5 @@ func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
return false return false
} }
return true return util.CompareIntp(s.Index, b.Index)
} }

View file

@ -1186,32 +1186,32 @@ func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) {
if in.Single != nil { if in.Single != nil {
in, out := &in.Single, &out.Single in, out := &in.Single, &out.Single
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.Agents != nil { if in.Agents != nil {
in, out := &in.Agents, &out.Agents in, out := &in.Agents, &out.Agents
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.DBServers != nil { if in.DBServers != nil {
in, out := &in.DBServers, &out.DBServers in, out := &in.DBServers, &out.DBServers
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.Coordinators != nil { if in.Coordinators != nil {
in, out := &in.Coordinators, &out.Coordinators in, out := &in.Coordinators, &out.Coordinators
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.SyncMasters != nil { if in.SyncMasters != nil {
in, out := &in.SyncMasters, &out.SyncMasters in, out := &in.SyncMasters, &out.SyncMasters
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.SyncWorkers != nil { if in.SyncWorkers != nil {
in, out := &in.SyncWorkers, &out.SyncWorkers in, out := &in.SyncWorkers, &out.SyncWorkers
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
return return
} }
@ -2368,6 +2368,11 @@ func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) {
*out = new(int64) *out = new(int64)
**out = **in **out = **in
} }
if in.IndexMethod != nil {
in, out := &in.IndexMethod, &out.IndexMethod
*out = new(ServerGroupIndexMethod)
**out = **in
}
return 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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) { func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) {
*out = *in *out = *in
if in.Index != nil {
in, out := &in.Index, &out.Index
*out = new(int)
**out = **in
}
return return
} }

View 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
}

View file

@ -153,6 +153,8 @@ type ServerGroupSpec struct {
AllowMemberRecreation *bool `json:"allowMemberRecreation,omitempty"` AllowMemberRecreation *bool `json:"allowMemberRecreation,omitempty"`
// TerminationGracePeriodSeconds override default TerminationGracePeriodSeconds for pods - via silent rotation // TerminationGracePeriodSeconds override default TerminationGracePeriodSeconds for pods - via silent rotation
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
// IndexMethod define group Indexing method
IndexMethod *ServerGroupIndexMethod `json:"indexMethod,omitempty"`
} }
// ServerGroupSpecSecurityContext contains specification for pod security context // ServerGroupSpecSecurityContext contains specification for pod security context
@ -539,6 +541,7 @@ func (s *ServerGroupSpec) validate() error {
shared.PrefixResourceError("volumes", s.Volumes.Validate()), shared.PrefixResourceError("volumes", s.Volumes.Validate()),
shared.PrefixResourceError("volumeMounts", s.VolumeMounts.Validate()), shared.PrefixResourceError("volumeMounts", s.VolumeMounts.Validate()),
shared.PrefixResourceError("initContainers", s.InitContainers.Validate()), shared.PrefixResourceError("initContainers", s.InitContainers.Validate()),
shared.PrefixResourceError("IndexMethod", s.IndexMethod.Validate()),
s.validateVolumes(), s.validateVolumes(),
) )
} }

View file

@ -20,7 +20,10 @@
package v2alpha1 package v2alpha1
import "github.com/arangodb/kube-arangodb/pkg/util"
type ServerGroupStatus struct { type ServerGroupStatus struct {
Index *int `json:"index,omitempty"`
} }
func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool { func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
@ -32,5 +35,5 @@ func (s *ServerGroupStatus) Equal(b *ServerGroupStatus) bool {
return false return false
} }
return true return util.CompareIntp(s.Index, b.Index)
} }

View file

@ -1186,32 +1186,32 @@ func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) {
if in.Single != nil { if in.Single != nil {
in, out := &in.Single, &out.Single in, out := &in.Single, &out.Single
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.Agents != nil { if in.Agents != nil {
in, out := &in.Agents, &out.Agents in, out := &in.Agents, &out.Agents
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.DBServers != nil { if in.DBServers != nil {
in, out := &in.DBServers, &out.DBServers in, out := &in.DBServers, &out.DBServers
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.Coordinators != nil { if in.Coordinators != nil {
in, out := &in.Coordinators, &out.Coordinators in, out := &in.Coordinators, &out.Coordinators
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.SyncMasters != nil { if in.SyncMasters != nil {
in, out := &in.SyncMasters, &out.SyncMasters in, out := &in.SyncMasters, &out.SyncMasters
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
if in.SyncWorkers != nil { if in.SyncWorkers != nil {
in, out := &in.SyncWorkers, &out.SyncWorkers in, out := &in.SyncWorkers, &out.SyncWorkers
*out = new(ServerGroupStatus) *out = new(ServerGroupStatus)
**out = **in (*in).DeepCopyInto(*out)
} }
return return
} }
@ -2368,6 +2368,11 @@ func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) {
*out = new(int64) *out = new(int64)
**out = **in **out = **in
} }
if in.IndexMethod != nil {
in, out := &in.IndexMethod, &out.IndexMethod
*out = new(ServerGroupIndexMethod)
**out = **in
}
return 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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) { func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) {
*out = *in *out = *in
if in.Index != nil {
in, out := &in.Index, &out.Index
*out = new(int)
**out = **in
}
return return
} }

View file

@ -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. // 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) { 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) { 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 { if err != nil {
d.log.Err(err).Str("group", group.AsRole()).Debug("Failed to create member") d.log.Err(err).Str("group", group.AsRole()).Debug("Failed to create member")
return false, errors.WithStack(err) return false, errors.WithStack(err)

View file

@ -23,8 +23,19 @@ package deployment
import ( import (
"context" "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 { func (d *Deployment) createInitialTopology(ctx context.Context) error {
return nil 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
}
}
}

View file

@ -30,12 +30,11 @@ import (
"github.com/arangodb/kube-arangodb/pkg/apis/shared" "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/deployment/reconcile" "github.com/arangodb/kube-arangodb/pkg/deployment/reconcile"
"github.com/arangodb/kube-arangodb/pkg/util/errors" "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 { func (d *Deployment) createAgencyMapping(ctx context.Context) error {
spec := d.GetSpec() spec := d.GetSpec()
status, _ := d.GetStatus() status := d.GetStatusSnapshot()
if !spec.Mode.HasAgents() { if !spec.Mode.HasAgents() {
return nil return nil
@ -65,12 +64,15 @@ func (d *Deployment) createAgencyMapping(ctx context.Context) error {
i.IDs = append(i.IDs, agents[id].ID) i.IDs = append(i.IDs, agents[id].ID)
} }
agentsStatus := status.GetServerGroupStatus(api.ServerGroupAgents)
for len(i.IDs) < *spec.Agents.Count { 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 { return d.WithStatusUpdate(ctx, func(s *api.DeploymentStatus) bool {
s.Agency = &i s.Agency = &i
s.UpdateServerGroupStatus(api.ServerGroupAgents, agentsStatus)
return true 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. // createMember creates member and adds it to the applicable member list.
// Note: This does not create any pods of PVCs // Note: This does not create any pods of PVCs
// Note: The updated status is not yet written to the apiserver. // 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) { func (d *Deployment) createMember(spec api.DeploymentSpec, status *api.DeploymentStatus, group api.ServerGroup, id string, apiObject *api.ArangoDeployment, mods ...reconcile.CreateMemberMod) (string, error) {
m, err := d.renderMember(status, group, id, apiObject) gs := status.GetServerGroupStatus(group)
m, err := d.renderMember(spec, status, &gs, group, id, apiObject)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -94,10 +98,12 @@ func (d *Deployment) createMember(status *api.DeploymentStatus, group api.Server
return "", err return "", err
} }
status.UpdateServerGroupStatus(group, gs)
return m.ID, nil 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 group == api.ServerGroupAgents {
if status.Agency == nil { if status.Agency == nil {
return nil, errors.New("Agency is not yet defined") return nil, errors.New("Agency is not yet defined")
@ -113,13 +119,7 @@ func (d *Deployment) renderMember(status *api.DeploymentStatus, group api.Server
} }
} else { } else {
if id == "" { if id == "" {
for { id = d.renderMemberID(spec, status, groupStatus, group)
id = names.GetArangodID(group)
if !status.Members.ContainsID(id) {
break
}
// Duplicate, try again
}
} }
} }
if id == "" { if id == "" {

View file

@ -30,7 +30,15 @@ import (
) )
func GetArangodID(group api.ServerGroup) string { 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 // GetArangodIDPrefix returns the prefix required ID's of arangod servers