mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] Add ArangoDeployment ServerGroupType (#1699)
This commit is contained in:
parent
e84f860c4f
commit
5772914840
19 changed files with 325 additions and 155 deletions
|
@ -7,6 +7,7 @@
|
|||
- (Bugfix) Fix Networking Client
|
||||
- (Feature) ConfigMap Inspector
|
||||
- (Feature) Envoy Image Layer
|
||||
- (Feature) Add ArangoDeployment ServerGroupType
|
||||
|
||||
## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23)
|
||||
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries
|
||||
|
|
|
@ -122,6 +122,20 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// Type returns the Group Type
|
||||
func (g ServerGroup) Type() ServerGroupType {
|
||||
switch g {
|
||||
case ServerGroupAgents, ServerGroupSingle, ServerGroupDBServers, ServerGroupCoordinators:
|
||||
return ServerGroupTypeArangoD
|
||||
case ServerGroupImageDiscovery:
|
||||
return ServerGroupTypeID
|
||||
case ServerGroupSyncMasters, ServerGroupSyncWorkers:
|
||||
return ServerGroupTypeArangoSync
|
||||
default:
|
||||
return ServerGroupTypeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// AsRole returns the "role" value for the given group.
|
||||
func (g ServerGroup) AsRole() string {
|
||||
switch g {
|
||||
|
|
|
@ -514,11 +514,12 @@ func (s ServerGroupSpec) Validate(group ServerGroup, used bool, mode DeploymentM
|
|||
for _, arg := range s.Args {
|
||||
parts := strings.Split(arg, "=")
|
||||
optionKey := strings.TrimSpace(parts[0])
|
||||
if group.IsArangod() {
|
||||
switch group.Type() {
|
||||
case ServerGroupTypeArangoD:
|
||||
if arangodOptions.IsCriticalOption(optionKey) {
|
||||
return errors.WithStack(errors.Wrapf(ValidationError, "Critical option '%s' cannot be overriden", optionKey))
|
||||
}
|
||||
} else if group.IsArangosync() {
|
||||
case ServerGroupTypeArangoSync:
|
||||
if arangosyncOptions.IsCriticalOption(optionKey) {
|
||||
return errors.WithStack(errors.Wrapf(ValidationError, "Critical option '%s' cannot be overriden", optionKey))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
// Copyright 2016-2024 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.
|
||||
|
@ -61,3 +61,14 @@ func TestServerGroupIsArangosync(t *testing.T) {
|
|||
assert.True(t, ServerGroupSyncMasters.IsArangosync())
|
||||
assert.True(t, ServerGroupSyncWorkers.IsArangosync())
|
||||
}
|
||||
|
||||
func TestServerGroupType(t *testing.T) {
|
||||
assert.Equal(t, ServerGroupTypeUnknown, ServerGroupUnknown.Type())
|
||||
assert.Equal(t, ServerGroupTypeID, ServerGroupImageDiscovery.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupSingle.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupAgents.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupDBServers.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupCoordinators.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoSync, ServerGroupSyncMasters.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoSync, ServerGroupSyncWorkers.Type())
|
||||
}
|
||||
|
|
30
pkg/apis/deployment/v1/server_group_type.go
Normal file
30
pkg/apis/deployment/v1/server_group_type.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2024 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
|
||||
|
||||
type ServerGroupType int
|
||||
|
||||
const (
|
||||
ServerGroupTypeUnknown ServerGroupType = iota
|
||||
ServerGroupTypeArangoD
|
||||
ServerGroupTypeArangoSync
|
||||
ServerGroupTypeID
|
||||
)
|
|
@ -122,6 +122,20 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// Type returns the Group Type
|
||||
func (g ServerGroup) Type() ServerGroupType {
|
||||
switch g {
|
||||
case ServerGroupAgents, ServerGroupSingle, ServerGroupDBServers, ServerGroupCoordinators:
|
||||
return ServerGroupTypeArangoD
|
||||
case ServerGroupImageDiscovery:
|
||||
return ServerGroupTypeID
|
||||
case ServerGroupSyncMasters, ServerGroupSyncWorkers:
|
||||
return ServerGroupTypeArangoSync
|
||||
default:
|
||||
return ServerGroupTypeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// AsRole returns the "role" value for the given group.
|
||||
func (g ServerGroup) AsRole() string {
|
||||
switch g {
|
||||
|
|
|
@ -514,11 +514,12 @@ func (s ServerGroupSpec) Validate(group ServerGroup, used bool, mode DeploymentM
|
|||
for _, arg := range s.Args {
|
||||
parts := strings.Split(arg, "=")
|
||||
optionKey := strings.TrimSpace(parts[0])
|
||||
if group.IsArangod() {
|
||||
switch group.Type() {
|
||||
case ServerGroupTypeArangoD:
|
||||
if arangodOptions.IsCriticalOption(optionKey) {
|
||||
return errors.WithStack(errors.Wrapf(ValidationError, "Critical option '%s' cannot be overriden", optionKey))
|
||||
}
|
||||
} else if group.IsArangosync() {
|
||||
case ServerGroupTypeArangoSync:
|
||||
if arangosyncOptions.IsCriticalOption(optionKey) {
|
||||
return errors.WithStack(errors.Wrapf(ValidationError, "Critical option '%s' cannot be overriden", optionKey))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
// Copyright 2016-2024 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.
|
||||
|
@ -61,3 +61,14 @@ func TestServerGroupIsArangosync(t *testing.T) {
|
|||
assert.True(t, ServerGroupSyncMasters.IsArangosync())
|
||||
assert.True(t, ServerGroupSyncWorkers.IsArangosync())
|
||||
}
|
||||
|
||||
func TestServerGroupType(t *testing.T) {
|
||||
assert.Equal(t, ServerGroupTypeUnknown, ServerGroupUnknown.Type())
|
||||
assert.Equal(t, ServerGroupTypeID, ServerGroupImageDiscovery.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupSingle.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupAgents.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupDBServers.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoD, ServerGroupCoordinators.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoSync, ServerGroupSyncMasters.Type())
|
||||
assert.Equal(t, ServerGroupTypeArangoSync, ServerGroupSyncWorkers.Type())
|
||||
}
|
||||
|
|
30
pkg/apis/deployment/v2alpha1/server_group_type.go
Normal file
30
pkg/apis/deployment/v2alpha1/server_group_type.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2024 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
|
||||
|
||||
type ServerGroupType int
|
||||
|
||||
const (
|
||||
ServerGroupTypeUnknown ServerGroupType = iota
|
||||
ServerGroupTypeArangoD
|
||||
ServerGroupTypeArangoSync
|
||||
ServerGroupTypeID
|
||||
)
|
|
@ -107,12 +107,14 @@ func createTestTLSVolume(serverGroupString, ID string) core.Volume {
|
|||
}
|
||||
|
||||
func createTestLifecycle(group api.ServerGroup) *core.Lifecycle {
|
||||
if group.IsArangosync() {
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
lifecycle, _ := k8sutil.NewLifecycleFinalizers()
|
||||
return lifecycle
|
||||
default:
|
||||
lifecycle, _ := k8sutil.NewLifecyclePort()
|
||||
return lifecycle
|
||||
}
|
||||
lifecycle, _ := k8sutil.NewLifecyclePort()
|
||||
return lifecycle
|
||||
}
|
||||
|
||||
func createTestToken(deployment *Deployment, testCase *testCaseStruct, paths []string) (string, error) {
|
||||
|
@ -864,52 +866,51 @@ func podDataSort() func(t *testing.T, p *core.Pod) {
|
|||
|
||||
func addLifecycle(name string, uuidRequired bool, license string, group api.ServerGroup) func(t *testing.T, p *core.Pod) {
|
||||
return func(t *testing.T, p *core.Pod) {
|
||||
if group.IsArangosync() {
|
||||
return
|
||||
}
|
||||
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
p.Spec.Containers[0].Env = append(k8sutil.GetLifecycleEnv(), p.Spec.Containers[0].Env...)
|
||||
if license != "" {
|
||||
p.Spec.Containers[0].Env = append([]core.EnvVar{
|
||||
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
|
||||
license, constants.SecretKeyToken)}, p.Spec.Containers[0].Env...)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := k8sutil.GetAnyVolumeByName(p.Spec.Volumes, shared.LifecycleVolumeName); !ok {
|
||||
p.Spec.Volumes = append([]core.Volume{k8sutil.LifecycleVolume()}, p.Spec.Volumes...)
|
||||
}
|
||||
if _, ok := k8sutil.GetAnyVolumeByName(p.Spec.Volumes, "arangod-data"); !ok {
|
||||
p.Spec.Volumes = append([]core.Volume{k8sutil.LifecycleVolume()}, p.Spec.Volumes...)
|
||||
}
|
||||
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
p.Spec.Containers[0].Lifecycle = createTestLifecycle(api.ServerGroupAgents)
|
||||
}
|
||||
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
if _, ok := k8sutil.GetAnyVolumeMountByName(p.Spec.Containers[0].VolumeMounts, "lifecycle"); !ok {
|
||||
p.Spec.Containers[0].VolumeMounts = append(p.Spec.Containers[0].VolumeMounts, k8sutil.LifecycleVolumeMount())
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
p.Spec.Containers[0].Env = append(k8sutil.GetLifecycleEnv(), p.Spec.Containers[0].Env...)
|
||||
if license != "" {
|
||||
p.Spec.Containers[0].Env = append([]core.EnvVar{
|
||||
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
|
||||
license, constants.SecretKeyToken)}, p.Spec.Containers[0].Env...)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := kresources.GetAnyContainerByName(p.Spec.InitContainers, "init-lifecycle"); !ok {
|
||||
if _, ok := k8sutil.GetAnyVolumeByName(p.Spec.Volumes, shared.LifecycleVolumeName); !ok {
|
||||
p.Spec.Volumes = append([]core.Volume{k8sutil.LifecycleVolume()}, p.Spec.Volumes...)
|
||||
}
|
||||
if _, ok := k8sutil.GetAnyVolumeByName(p.Spec.Volumes, "arangod-data"); !ok {
|
||||
p.Spec.Volumes = append([]core.Volume{k8sutil.LifecycleVolume()}, p.Spec.Volumes...)
|
||||
}
|
||||
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
p.Spec.Containers[0].Lifecycle = createTestLifecycle(api.ServerGroupAgents)
|
||||
}
|
||||
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
if _, ok := k8sutil.GetAnyVolumeMountByName(p.Spec.Containers[0].VolumeMounts, "lifecycle"); !ok {
|
||||
p.Spec.Containers[0].VolumeMounts = append(p.Spec.Containers[0].VolumeMounts, k8sutil.LifecycleVolumeMount())
|
||||
}
|
||||
|
||||
if _, ok := kresources.GetAnyContainerByName(p.Spec.InitContainers, "init-lifecycle"); !ok {
|
||||
p.Spec.InitContainers = append(
|
||||
[]core.Container{createTestLifecycleContainer(emptyResources)},
|
||||
p.Spec.InitContainers...,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := kresources.GetAnyContainerByName(p.Spec.InitContainers, "uuid"); !ok {
|
||||
binaryPath, _ := os.Executable()
|
||||
p.Spec.InitContainers = append(
|
||||
[]core.Container{createTestLifecycleContainer(emptyResources)},
|
||||
[]core.Container{
|
||||
k8sutil.ArangodInitContainer("uuid", name, "rocksdb", binaryPath, testImageOperator, uuidRequired, securityContext.NewSecurityContext()),
|
||||
},
|
||||
p.Spec.InitContainers...,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := kresources.GetAnyContainerByName(p.Spec.InitContainers, "uuid"); !ok {
|
||||
binaryPath, _ := os.Executable()
|
||||
p.Spec.InitContainers = append(
|
||||
[]core.Container{
|
||||
k8sutil.ArangodInitContainer("uuid", name, "rocksdb", binaryPath, testImageOperator, uuidRequired, securityContext.NewSecurityContext()),
|
||||
},
|
||||
p.Spec.InitContainers...,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/logging"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/arangod"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||
)
|
||||
|
@ -123,13 +124,20 @@ func (s *stateInspector) RefreshState(ctx context.Context, members api.Deploymen
|
|||
ctxChild, cancel := globals.GetGlobalTimeouts().ArangoDCheck().WithTimeout(ctx)
|
||||
defer cancel()
|
||||
|
||||
if members[id].Group.IsArangosync() {
|
||||
switch members[id].Group.Type() {
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
results[id] = s.fetchArangosyncMemberState(ctxChild, members[id])
|
||||
} else {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
results[id] = s.fetchServerMemberState(ctxChild, members[id], servingGroup)
|
||||
if results[id].IsServing() {
|
||||
client = results[id].client
|
||||
}
|
||||
default:
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to fetch Health for an unknown group: %s", members[id].Group.AsRole())
|
||||
results[id] = State{
|
||||
IsClusterHealthy: false,
|
||||
serving: false,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -155,22 +163,26 @@ func (s *stateInspector) RefreshState(ctx context.Context, members api.Deploymen
|
|||
continue
|
||||
}
|
||||
|
||||
if members[i].Group.IsArangosync() {
|
||||
// ArangoSync is considered as healthy when it is possible to fetch version.
|
||||
results[i].IsClusterHealthy = true
|
||||
continue
|
||||
}
|
||||
|
||||
if v, ok := h.Members[driver.ServerID(m.Member.ID)]; ok {
|
||||
results[i].IsClusterHealthy = v.Status == driver.ServerStatusGood
|
||||
if results[i].IsServing() && v.SyncStatus == driver.ServerSyncStatusServing {
|
||||
if cs.client == nil || util.Rand().Intn(100) > 50 {
|
||||
// Set client from nil or take next client with 50% probability.
|
||||
cs.client = results[i].client
|
||||
cs.Version = results[i].Version
|
||||
switch members[i].Group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
if v, ok := h.Members[driver.ServerID(m.Member.ID)]; ok {
|
||||
results[i].IsClusterHealthy = v.Status == driver.ServerStatusGood
|
||||
if results[i].IsServing() && v.SyncStatus == driver.ServerSyncStatusServing {
|
||||
if cs.client == nil || util.Rand().Intn(100) > 50 {
|
||||
// Set client from nil or take next client with 50% probability.
|
||||
cs.client = results[i].client
|
||||
cs.Version = results[i].Version
|
||||
}
|
||||
}
|
||||
}
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
// ArangoSync is considered as healthy when it is possible to fetch version.
|
||||
results[i].IsClusterHealthy = true
|
||||
default:
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to fetch Health for an unknown group: %s", members[i].Group.AsRole())
|
||||
results[i].IsClusterHealthy = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service"
|
||||
|
@ -41,7 +42,8 @@ func GenerateMemberEndpoint(services service.Inspector, apiObject meta.Object, s
|
|||
}
|
||||
|
||||
func GenerateMemberEndpointFromService(svc *core.Service, apiObject meta.Object, spec api.DeploymentSpec, group api.ServerGroup, member api.MemberStatus) (string, error) {
|
||||
if group.IsArangod() {
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
switch method := spec.CommunicationMethod.Get(); method {
|
||||
case api.DeploymentCommunicationMethodDNS, api.DeploymentCommunicationMethodHeadlessDNS:
|
||||
return k8sutil.CreateServiceDNSNameWithDomain(svc, spec.ClusterDomain), nil
|
||||
|
@ -60,7 +62,9 @@ func GenerateMemberEndpointFromService(svc *core.Service, apiObject meta.Object,
|
|||
default:
|
||||
return k8sutil.CreatePodDNSNameWithDomain(apiObject, spec.ClusterDomain, group.AsRole(), member.ID), nil
|
||||
}
|
||||
} else {
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
return k8sutil.CreateSyncMasterClientServiceDNSNameWithDomain(apiObject, spec.ClusterDomain), nil
|
||||
default:
|
||||
return "", assertion.InvalidGroupKey.Assert(true, "Unable to create Endpoint for an unknown group: %s", group.AsRole())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
// Copyright 2016-2024 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.
|
||||
|
@ -29,6 +29,7 @@ import (
|
|||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/client"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||
)
|
||||
|
@ -72,22 +73,27 @@ func (a *actionWaitForMemberUp) CheckProgress(ctx context.Context) (bool, bool,
|
|||
ctxChild, cancel := globals.GetGlobalTimeouts().ArangoD().WithTimeout(ctx)
|
||||
defer cancel()
|
||||
|
||||
if a.action.Group.IsArangosync() {
|
||||
switch a.action.Group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
switch a.actionCtx.GetMode() {
|
||||
case api.DeploymentModeSingle:
|
||||
return a.checkProgressSingle(ctxChild)
|
||||
case api.DeploymentModeActiveFailover:
|
||||
if a.action.Group == api.ServerGroupAgents {
|
||||
return a.checkProgressAgent()
|
||||
}
|
||||
return a.checkProgressSingleInActiveFailover(ctxChild)
|
||||
default:
|
||||
if a.action.Group == api.ServerGroupAgents {
|
||||
return a.checkProgressAgent()
|
||||
}
|
||||
return a.checkProgressCluster(ctx)
|
||||
}
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
return a.checkProgressArangoSync(ctxChild)
|
||||
}
|
||||
switch a.actionCtx.GetMode() {
|
||||
case api.DeploymentModeSingle:
|
||||
return a.checkProgressSingle(ctxChild)
|
||||
case api.DeploymentModeActiveFailover:
|
||||
if a.action.Group == api.ServerGroupAgents {
|
||||
return a.checkProgressAgent()
|
||||
}
|
||||
return a.checkProgressSingleInActiveFailover(ctxChild)
|
||||
default:
|
||||
if a.action.Group == api.ServerGroupAgents {
|
||||
return a.checkProgressAgent()
|
||||
}
|
||||
return a.checkProgressCluster(ctx)
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to execute action WaitForMemberUp for an unknown group: %s", a.action.Group.AsRole())
|
||||
return true, false, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/deployment/client"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
|
||||
|
@ -157,7 +158,8 @@ func (s shutdownHelperAPI) Start(ctx context.Context) (bool, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if group.IsArangod() {
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
// Invoke shutdown endpoint
|
||||
c, err := s.actionCtx.GetMembersState().GetMemberClient(s.action.MemberID)
|
||||
if err != nil {
|
||||
|
@ -177,14 +179,17 @@ func (s shutdownHelperAPI) Start(ctx context.Context) (bool, error) {
|
|||
s.log.Err(err).Debug("Failed to shutdown member")
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
} else if group.IsArangosync() {
|
||||
return false, nil
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
// Terminate pod
|
||||
if err := cache.Client().Kubernetes().CoreV1().Pods(cache.Namespace()).Delete(ctx, podName, meta.DeleteOptions{}); err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
return false, nil
|
||||
default:
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to execute ShutdownAction for an unknown group: %s", group.AsRole())
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// CheckProgress returns true when pod is terminated.
|
||||
|
|
|
@ -41,6 +41,7 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/crypto"
|
||||
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
|
||||
|
@ -542,10 +543,15 @@ func (r *Reconciler) keyfileRenewalRequired(ctx context.Context, apiObject k8sut
|
|||
|
||||
// Verify AltNames
|
||||
var altNames memberTls.KeyfileInput
|
||||
if group.IsArangosync() {
|
||||
altNames, err = memberTls.GetSyncAltNames(apiObject, spec, tlsSpec, group, member)
|
||||
} else {
|
||||
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
altNames, err = memberTls.GetServerAltNames(apiObject, spec, tlsSpec, service, group, member)
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
altNames, err = memberTls.GetSyncAltNames(apiObject, spec, tlsSpec, group, member)
|
||||
default:
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to check TLS Key Renewal for an unknown group: %s", group.AsRole())
|
||||
return false, false
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -568,37 +574,44 @@ func (r *Reconciler) keyfileRenewalRequired(ctx context.Context, apiObject k8sut
|
|||
}
|
||||
|
||||
// Ensure secret is propagated only on 3.7.0+ enterprise and inplace mode
|
||||
if mode == api.TLSRotateModeInPlace && group.IsArangod() {
|
||||
conn, err := context.GetMembersState().GetMemberClient(member.ID)
|
||||
if err != nil {
|
||||
r.planLogger.Err(err).Warn("Unable to get client")
|
||||
return false, false
|
||||
}
|
||||
if mode == api.TLSRotateModeInPlace {
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
conn, err := context.GetMembersState().GetMemberClient(member.ID)
|
||||
if err != nil {
|
||||
r.planLogger.Err(err).Warn("Unable to get client")
|
||||
return false, false
|
||||
}
|
||||
|
||||
s, exists := cachedStatus.Secret().V1().GetSimple(k8sutil.CreateTLSKeyfileSecretName(apiObject.GetName(), group.AsRole(), member.ID))
|
||||
if !exists {
|
||||
r.planLogger.Warn("Keyfile secret is missing")
|
||||
return false, false
|
||||
}
|
||||
s, exists := cachedStatus.Secret().V1().GetSimple(k8sutil.CreateTLSKeyfileSecretName(apiObject.GetName(), group.AsRole(), member.ID))
|
||||
if !exists {
|
||||
r.planLogger.Warn("Keyfile secret is missing")
|
||||
return false, false
|
||||
}
|
||||
|
||||
c := client.NewClient(conn.Connection(), r.log)
|
||||
tls, err := c.GetTLS(ctx)
|
||||
if err != nil {
|
||||
r.planLogger.Err(err).Warn("Unable to get tls details")
|
||||
return false, false
|
||||
}
|
||||
c := client.NewClient(conn.Connection(), r.log)
|
||||
tls, err := c.GetTLS(ctx)
|
||||
if err != nil {
|
||||
r.planLogger.Err(err).Warn("Unable to get tls details")
|
||||
return false, false
|
||||
}
|
||||
|
||||
keyfile, ok := s.Data[constants.SecretTLSKeyfile]
|
||||
if !ok {
|
||||
r.planLogger.Warn("Keyfile secret is invalid")
|
||||
return false, false
|
||||
}
|
||||
keyfile, ok := s.Data[constants.SecretTLSKeyfile]
|
||||
if !ok {
|
||||
r.planLogger.Warn("Keyfile secret is invalid")
|
||||
return false, false
|
||||
}
|
||||
|
||||
keyfileSha := util.SHA256(keyfile)
|
||||
keyfileSha := util.SHA256(keyfile)
|
||||
|
||||
if tls.Result.KeyFile.GetSHA().Checksum() != keyfileSha {
|
||||
r.planLogger.Str("current", tls.Result.KeyFile.GetSHA().Checksum()).Str("desired", keyfileSha).Debug("Unable to get tls details")
|
||||
return true, false
|
||||
if tls.Result.KeyFile.GetSHA().Checksum() != keyfileSha {
|
||||
r.planLogger.Str("current", tls.Result.KeyFile.GetSHA().Checksum()).Str("desired", keyfileSha).Debug("Unable to get tls details")
|
||||
return true, false
|
||||
}
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
break
|
||||
default:
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to check TLS Key Renewal for an unknown group: %s", group.AsRole())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/reconciler"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||
|
@ -335,7 +336,8 @@ func (r *Resources) RenderPodForMember(ctx context.Context, acs sutil.ACS, spec
|
|||
podName := k8sutil.CreatePodName(apiObject.GetName(), roleAbbr, m.ID, CreatePodSuffix(spec))
|
||||
|
||||
var podCreator interfaces.PodCreator
|
||||
if group.IsArangod() {
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
// Prepare arguments
|
||||
autoUpgrade := m.Conditions.IsTrue(api.ConditionTypeAutoUpgrade) || spec.Upgrade.Get().AutoUpgrade
|
||||
|
||||
|
@ -353,7 +355,7 @@ func (r *Resources) RenderPodForMember(ctx context.Context, acs sutil.ACS, spec
|
|||
arangoMember: *member,
|
||||
cachedStatus: cache,
|
||||
}
|
||||
} else if group.IsArangosync() {
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
// Check image
|
||||
if !imageInfo.Enterprise {
|
||||
log.Str("image", spec.GetImage()).Debug("Image is not an enterprise image")
|
||||
|
@ -377,8 +379,8 @@ func (r *Resources) RenderPodForMember(ctx context.Context, acs sutil.ACS, spec
|
|||
memberStatus: m,
|
||||
cachedStatus: cache,
|
||||
}
|
||||
} else {
|
||||
return nil, errors.Errorf("unable to render Pod")
|
||||
default:
|
||||
return nil, assertion.InvalidGroupKey.Assert(true, "Unable to render pod for an unknown group: %s", group.AsRole())
|
||||
}
|
||||
|
||||
pod, err := RenderArangoPod(ctx, cache, apiObject, role, m.ID, podName, podCreator)
|
||||
|
@ -468,7 +470,8 @@ func (r *Resources) createPodForMember(ctx context.Context, cachedStatus inspect
|
|||
|
||||
newPhase := api.MemberPhaseCreated
|
||||
// Create pod
|
||||
if group.IsArangod() {
|
||||
switch group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
// Prepare arguments
|
||||
autoUpgrade := m.Conditions.IsTrue(api.ConditionTypeAutoUpgrade)
|
||||
if autoUpgrade {
|
||||
|
@ -507,7 +510,7 @@ func (r *Resources) createPodForMember(ctx context.Context, cachedStatus inspect
|
|||
} else {
|
||||
log.Str("pod-name", pod.Name).Debug("Created pod with predefined image")
|
||||
}
|
||||
} else if group.IsArangosync() {
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
// Check monitoring token secret
|
||||
if group == api.ServerGroupSyncMasters {
|
||||
// Create TLS secret
|
||||
|
@ -545,6 +548,8 @@ func (r *Resources) createPodForMember(ctx context.Context, cachedStatus inspect
|
|||
m.Pod.Propagate(&m)
|
||||
|
||||
log.Str("pod-name", pod.Name).Debug("Created pod")
|
||||
default:
|
||||
return assertion.InvalidGroupKey.Assert(true, "Unable to create pod for an unknown group: %s", group.AsRole())
|
||||
}
|
||||
|
||||
member.GetPhaseExecutor().Execute(r.context.GetAPIObject(), spec, group, &m, api.Action{}, newPhase)
|
||||
|
|
|
@ -598,7 +598,7 @@ func (m *MemberArangoDPod) Annotations() map[string]string {
|
|||
func (m *MemberArangoDPod) Labels() map[string]string {
|
||||
l := collection.ReservedLabels().Filter(collection.MergeAnnotations(m.spec.Labels, m.groupSpec.Labels))
|
||||
|
||||
if m.group.IsArangod() && m.status.Topology != nil && m.deploymentStatus.Topology.Enabled() && m.deploymentStatus.Topology.ID == m.status.Topology.ID {
|
||||
if m.status.Topology != nil && m.deploymentStatus.Topology.Enabled() && m.deploymentStatus.Topology.ID == m.status.Topology.ID {
|
||||
if l == nil {
|
||||
l = map[string]string{}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||
"github.com/arangodb/kube-arangodb/pkg/metrics"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||
|
@ -129,36 +130,41 @@ func (r *Resources) EnsureSecrets(ctx context.Context, cachedStatus inspectorInt
|
|||
}
|
||||
|
||||
if err := reconcileRequired.ParallelAll(len(members), func(id int) error {
|
||||
if !members[id].Group.IsArangod() {
|
||||
switch members[id].Group.Type() {
|
||||
case api.ServerGroupTypeArangoD:
|
||||
memberName := members[id].Member.ArangoMemberName(r.context.GetAPIObject().GetName(), members[id].Group)
|
||||
|
||||
member, ok := cachedStatus.ArangoMember().V1().GetSimple(memberName)
|
||||
if !ok {
|
||||
return errors.Errorf("Member %s not found", memberName)
|
||||
}
|
||||
|
||||
service, ok := cachedStatus.Service().V1().GetSimple(memberName)
|
||||
if !ok {
|
||||
return errors.Errorf("Service of member %s not found", memberName)
|
||||
}
|
||||
|
||||
tlsKeyfileSecretName := k8sutil.AppendTLSKeyfileSecretPostfix(member.GetName())
|
||||
if _, exists := cachedStatus.Secret().V1().GetSimple(tlsKeyfileSecretName); !exists {
|
||||
serverNames, err := tls.GetServerAltNames(apiObject, spec, spec.TLS, service, members[id].Group, members[id].Member)
|
||||
if err != nil {
|
||||
return errors.WithStack(errors.Wrapf(err, "Failed to render alt names"))
|
||||
}
|
||||
owner := member.AsOwner()
|
||||
if created, err := createTLSServerCertificate(ctx, log, cachedStatus, secrets, serverNames, spec.TLS, tlsKeyfileSecretName, &owner); err != nil && !kerrors.IsAlreadyExists(err) {
|
||||
return errors.WithStack(errors.Wrapf(err, "Failed to create TLS keyfile secret"))
|
||||
} else if created {
|
||||
reconcileRequired.Required()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case api.ServerGroupTypeArangoSync:
|
||||
// Nothing to do
|
||||
return nil
|
||||
default:
|
||||
assertion.InvalidGroupKey.Assert(true, "Unable to create TLS Secret an unknown group: %s", members[id].Group.AsRole())
|
||||
return nil
|
||||
}
|
||||
|
||||
memberName := members[id].Member.ArangoMemberName(r.context.GetAPIObject().GetName(), members[id].Group)
|
||||
|
||||
member, ok := cachedStatus.ArangoMember().V1().GetSimple(memberName)
|
||||
if !ok {
|
||||
return errors.Errorf("Member %s not found", memberName)
|
||||
}
|
||||
|
||||
service, ok := cachedStatus.Service().V1().GetSimple(memberName)
|
||||
if !ok {
|
||||
return errors.Errorf("Service of member %s not found", memberName)
|
||||
}
|
||||
|
||||
tlsKeyfileSecretName := k8sutil.AppendTLSKeyfileSecretPostfix(member.GetName())
|
||||
if _, exists := cachedStatus.Secret().V1().GetSimple(tlsKeyfileSecretName); !exists {
|
||||
serverNames, err := tls.GetServerAltNames(apiObject, spec, spec.TLS, service, members[id].Group, members[id].Member)
|
||||
if err != nil {
|
||||
return errors.WithStack(errors.Wrapf(err, "Failed to render alt names"))
|
||||
}
|
||||
owner := member.AsOwner()
|
||||
if created, err := createTLSServerCertificate(ctx, log, cachedStatus, secrets, serverNames, spec.TLS, tlsKeyfileSecretName, &owner); err != nil && !kerrors.IsAlreadyExists(err) {
|
||||
return errors.WithStack(errors.Wrapf(err, "Failed to create TLS keyfile secret"))
|
||||
} else if created {
|
||||
reconcileRequired.Required()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Section(err, "TLS TrustStore")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
|
||||
// Copyright 2023-2024 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.
|
||||
|
@ -22,6 +22,8 @@ package assertion
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
)
|
||||
|
||||
type Key string
|
||||
|
@ -30,19 +32,20 @@ const (
|
|||
KeyUnknown Key = ""
|
||||
DeprecatedActionKey Key = "DeprecatedAction"
|
||||
CommunityLicenseCheckKey Key = "CommunityLicenseCheck"
|
||||
InvalidGroupKey Key = "InvalidGroup"
|
||||
)
|
||||
|
||||
func (k Key) Assert(condition bool, msg string, args ...interface{}) {
|
||||
assert(2, condition, k, msg, args...)
|
||||
func (k Key) Assert(condition bool, msg string, args ...interface{}) error {
|
||||
return assert(2, condition, k, msg, args...)
|
||||
}
|
||||
|
||||
func Assert(condition bool, key Key, msg string, args ...interface{}) {
|
||||
assert(2, condition, key, msg, args...)
|
||||
func Assert(condition bool, key Key, msg string, args ...interface{}) error {
|
||||
return assert(2, condition, key, msg, args...)
|
||||
}
|
||||
|
||||
func assert(skip int, condition bool, key Key, msg string, args ...interface{}) {
|
||||
func assert(skip int, condition bool, key Key, msg string, args ...interface{}) error {
|
||||
if !condition {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
metricsObject.incKeyMetric(key)
|
||||
|
@ -50,4 +53,6 @@ func assert(skip int, condition bool, key Key, msg string, args ...interface{})
|
|||
frames := frames(skip)
|
||||
|
||||
_assert(frames, fmt.Sprintf(msg, args...))
|
||||
|
||||
return errors.WithStack(errors.Errorf("Error Assertion `%s`: %s", key, fmt.Sprintf(msg, args...)))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue