1
0
Fork 0
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:
Nikita Vaniasin 2023-12-08 13:38:13 +01:00 committed by GitHub
parent b2c88f6ad8
commit cff60f2eab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 172 additions and 5 deletions

View file

@ -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

View file

@ -46,10 +46,15 @@ rules:
- "cronjobs"
- "jobs"
verbs: ["*"]
- apiGroups: ["apps"]
resources:
- "statefulsets"
verbs: ["*"]
- apiGroups: [""]
resources:
- "pods"
- "secrets"
- "services"
- "serviceaccounts"
verbs: ["*"]
{{- end }}

View file

@ -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"
)

View file

@ -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) {

View file

@ -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

View file

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

View file

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

View file

@ -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

View file

@ -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

View file

@ -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)