mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
(Feature) (ML) Handler for Extension StatefulSet and Service (#1528)
This commit is contained in:
parent
b2c88f6ad8
commit
cff60f2eab
11 changed files with 172 additions and 5 deletions
|
@ -31,6 +31,7 @@
|
|||
- (Feature) (ML) Unify Images, Resources and Lifecycle
|
||||
- (Improvement) (ML) CronJob status update
|
||||
- (Improvement) (ML) Job Sidecar Shutdown
|
||||
- (Feature) (ML) Handler for Extension StatefulSet and Service
|
||||
|
||||
## [1.2.35](https://github.com/arangodb/kube-arangodb/tree/1.2.35) (2023-11-06)
|
||||
- (Maintenance) Update go-driver to v1.6.0, update IsNotFound() checks
|
||||
|
|
|
@ -46,10 +46,15 @@ rules:
|
|||
- "cronjobs"
|
||||
- "jobs"
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["apps"]
|
||||
resources:
|
||||
- "statefulsets"
|
||||
verbs: ["*"]
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- "pods"
|
||||
- "secrets"
|
||||
- "services"
|
||||
- "serviceaccounts"
|
||||
verbs: ["*"]
|
||||
{{- end }}
|
||||
|
|
|
@ -28,6 +28,7 @@ const (
|
|||
ExtensionBootstrapCompletedCondition api.ConditionType = "BootstrapCompleted"
|
||||
ExtensionMetadataServiceValidCondition api.ConditionType = "MetadataServiceValid"
|
||||
ExtensionServiceAccountReadyCondition api.ConditionType = "ServiceAccountReady"
|
||||
ExtensionStatefulSetReadyCondition api.ConditionType = "ExtensionDeploymentReady"
|
||||
LicenseValidCondition api.ConditionType = "LicenseValid"
|
||||
CronJobSyncedCondition api.ConditionType = "CronJobSynced"
|
||||
)
|
||||
|
|
|
@ -207,7 +207,7 @@ func (h *handler) getDeploymentMutex(namespace, deployment string) *sync.Mutex {
|
|||
}
|
||||
|
||||
func (h *handler) Handle(_ context.Context, item operation.Item) error {
|
||||
// Get Backup object. It also covers NotFound case
|
||||
// Get object. It also covers NotFound case
|
||||
b, err := h.client.BackupV1().ArangoBackups(item.Namespace).Get(context.Background(), item.Name, meta.GetOptions{})
|
||||
if err != nil {
|
||||
if apiErrors.IsNotFound(err) {
|
||||
|
|
|
@ -70,7 +70,7 @@ func (h *handler) Handle(_ context.Context, item operation.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Get Backup object. It also cover NotFound case
|
||||
// Get object. It also cover NotFound case
|
||||
policy, err := h.client.BackupV1().ArangoBackupPolicies(item.Namespace).Get(context.Background(), item.Name, meta.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -22,6 +22,7 @@ package license
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Status int
|
||||
|
@ -67,6 +68,28 @@ func (s Status) Valid() bool {
|
|||
func (s Status) Validate(feature Feature, subFeatures ...Feature) Status {
|
||||
return s
|
||||
}
|
||||
func (s Status) String() string {
|
||||
switch s {
|
||||
case StatusMissing:
|
||||
return "Missing"
|
||||
case StatusInvalid:
|
||||
return "Invalid"
|
||||
case StatusInvalidSignature:
|
||||
return "InvalidSignature"
|
||||
case StatusNotYetValid:
|
||||
return "NotYetValid"
|
||||
case StatusNotAnymoreValid:
|
||||
return "NotAnymoreValid"
|
||||
case StatusFeatureNotEnabled:
|
||||
return "FeatureNotEnabled"
|
||||
case StatusFeatureExpired:
|
||||
return "FeatureExpired"
|
||||
case StatusValid:
|
||||
return "Valid"
|
||||
default:
|
||||
return strconv.Itoa(int(s))
|
||||
}
|
||||
}
|
||||
|
||||
type Feature string
|
||||
|
||||
|
|
29
pkg/util/helpers.go
Normal file
29
pkg/util/helpers.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 util
|
||||
|
||||
// Ter implements a ternary operation: return cond ? a : b;
|
||||
func Ter[T any](cond bool, a T, b T) T {
|
||||
if cond {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -24,7 +24,9 @@ import (
|
|||
core "k8s.io/api/core/v1"
|
||||
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
)
|
||||
|
||||
// CreateSecurityContext returns security context.
|
||||
|
@ -37,3 +39,29 @@ func CreateSecurityContext(spec *api.ServerGroupSpecSecurityContext) *core.Secur
|
|||
func CreatePodSecurityContext(spec *api.ServerGroupSpecSecurityContext) *core.PodSecurityContext {
|
||||
return spec.NewPodSecurityContext(features.SecuredContainers().Enabled())
|
||||
}
|
||||
|
||||
func CreateSecurePodSecurityContext() *core.PodSecurityContext {
|
||||
psc := &core.PodSecurityContext{
|
||||
RunAsUser: util.NewType[int64](shared.DefaultRunAsUser),
|
||||
RunAsGroup: util.NewType[int64](shared.DefaultRunAsGroup),
|
||||
RunAsNonRoot: util.NewType(true),
|
||||
FSGroup: util.NewType[int64](shared.DefaultFSGroup),
|
||||
}
|
||||
|
||||
return psc
|
||||
}
|
||||
|
||||
func CreateDefaultSecurityContext() *core.SecurityContext {
|
||||
r := &core.SecurityContext{
|
||||
RunAsUser: util.NewType[int64](shared.DefaultRunAsUser),
|
||||
RunAsGroup: util.NewType[int64](shared.DefaultRunAsGroup),
|
||||
RunAsNonRoot: util.NewType(true),
|
||||
ReadOnlyRootFilesystem: util.NewType(true),
|
||||
Capabilities: &core.Capabilities{
|
||||
Drop: []core.Capability{
|
||||
"ALL",
|
||||
},
|
||||
},
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
// Copyright 2016-2023 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.
|
||||
|
@ -50,8 +50,12 @@ const (
|
|||
LabelKeyArangoActive = "deployment.arangodb.com/active"
|
||||
// LabelValueArangoActive is the value of the label used to mark members as active.
|
||||
LabelValueArangoActive = "true"
|
||||
// AppName is the fixed value for the "app" label
|
||||
// LabelKeyArangoMLStatefulSet is the key of the label used to define k8s StatefulSet for ML Extension
|
||||
LabelKeyArangoMLStatefulSet = "ml.arangodb.com/statefulset"
|
||||
// AppName is the value for the "app" label
|
||||
AppName = "arangodb"
|
||||
// AppArangoML is the value for the "app" label
|
||||
AppArangoML = "arangoml"
|
||||
)
|
||||
|
||||
// AddOwnerRefToObject adds given owner reference to given object
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
batch "k8s.io/api/batch/v1"
|
||||
core "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
|
@ -120,12 +121,24 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
|||
vl := *v
|
||||
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **core.Service:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := k8s.CoreV1().Services(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **core.ServiceAccount:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **apps.StatefulSet:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := k8s.AppsV1().StatefulSets(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **api.ArangoDeployment:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -223,12 +236,23 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
|||
vl := *v
|
||||
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **core.Service:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := k8s.CoreV1().Services(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **core.ServiceAccount:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **apps.StatefulSet:
|
||||
require.NotNil(t, v)
|
||||
vl := *v
|
||||
_, err := k8s.AppsV1().StatefulSets(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **api.ArangoDeployment:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -450,6 +474,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
|
|||
} else {
|
||||
*v = vn
|
||||
}
|
||||
case **core.Service:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
|
||||
vn, err := k8s.CoreV1().Services(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
*v = nil
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
} else {
|
||||
*v = vn
|
||||
}
|
||||
case **core.ServiceAccount:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -465,6 +504,20 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
|
|||
} else {
|
||||
*v = vn
|
||||
}
|
||||
case **apps.StatefulSet:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
vn, err := k8s.AppsV1().StatefulSets(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
*v = nil
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
} else {
|
||||
*v = vn
|
||||
}
|
||||
case **api.ArangoDeployment:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -616,7 +669,7 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
|
|||
*v = vn
|
||||
}
|
||||
default:
|
||||
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
||||
require.Fail(t, fmt.Sprintf("Unable to get object: %s", reflect.TypeOf(v).String()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -649,12 +702,24 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
|
|||
v.SetSelfLink(fmt.Sprintf("/api/v1/secrets/%s/%s",
|
||||
object.GetNamespace(),
|
||||
object.GetName()))
|
||||
case *core.Service:
|
||||
v.Kind = "Service"
|
||||
v.APIVersion = "v1"
|
||||
v.SetSelfLink(fmt.Sprintf("/api/v1/services/%s/%s",
|
||||
object.GetNamespace(),
|
||||
object.GetName()))
|
||||
case *core.ServiceAccount:
|
||||
v.Kind = "ServiceAccount"
|
||||
v.APIVersion = "v1"
|
||||
v.SetSelfLink(fmt.Sprintf("/api/v1/serviceaccounts/%s/%s",
|
||||
object.GetNamespace(),
|
||||
object.GetName()))
|
||||
case *apps.StatefulSet:
|
||||
v.Kind = "StatefulSet"
|
||||
v.APIVersion = "v1"
|
||||
v.SetSelfLink(fmt.Sprintf("/api/apps/v1/statefulsets/%s/%s",
|
||||
object.GetNamespace(),
|
||||
object.GetName()))
|
||||
case *api.ArangoDeployment:
|
||||
v.Kind = deployment.ArangoDeploymentResourceKind
|
||||
v.APIVersion = api.SchemeGroupVersion.String()
|
||||
|
@ -790,10 +855,18 @@ func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.
|
|||
item.Group = ""
|
||||
item.Version = "v1"
|
||||
item.Kind = "Secret"
|
||||
case *core.Service:
|
||||
item.Group = ""
|
||||
item.Version = "v1"
|
||||
item.Kind = "Service"
|
||||
case *core.ServiceAccount:
|
||||
item.Group = ""
|
||||
item.Version = "v1"
|
||||
item.Kind = "ServiceAccount"
|
||||
case *apps.StatefulSet:
|
||||
item.Group = "apps"
|
||||
item.Version = "v1"
|
||||
item.Kind = "StatefulSet"
|
||||
case *api.ArangoDeployment:
|
||||
item.Group = deployment.ArangoDeploymentGroupName
|
||||
item.Version = api.ArangoDeploymentVersion
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
batch "k8s.io/api/batch/v1"
|
||||
core "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
|
@ -64,6 +65,8 @@ func Test_NewMetaObject(t *testing.T) {
|
|||
NewMetaObjectRun[*core.Pod](t)
|
||||
NewMetaObjectRun[*core.Secret](t)
|
||||
NewMetaObjectRun[*core.ServiceAccount](t)
|
||||
NewMetaObjectRun[*core.Service](t)
|
||||
NewMetaObjectRun[*apps.StatefulSet](t)
|
||||
NewMetaObjectRun[*rbac.Role](t)
|
||||
NewMetaObjectRun[*rbac.RoleBinding](t)
|
||||
NewMetaObjectRun[*rbac.ClusterRole](t)
|
||||
|
|
Loading…
Reference in a new issue