Skip to content

Commit cff60f2

Browse files
(Feature) (ML) Handler for Extension StatefulSet and Service (#1528)
1 parent b2c88f6 commit cff60f2

File tree

11 files changed

+172
-5
lines changed

11 files changed

+172
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
- (Feature) (ML) Unify Images, Resources and Lifecycle
3232
- (Improvement) (ML) CronJob status update
3333
- (Improvement) (ML) Job Sidecar Shutdown
34+
- (Feature) (ML) Handler for Extension StatefulSet and Service
3435

3536
## [1.2.35](https://github.com/arangodb/kube-arangodb/tree/1.2.35) (2023-11-06)
3637
- (Maintenance) Update go-driver to v1.6.0, update IsNotFound() checks

chart/kube-arangodb/templates/ml-operator/role.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,15 @@ rules:
4646
- "cronjobs"
4747
- "jobs"
4848
verbs: ["*"]
49+
- apiGroups: ["apps"]
50+
resources:
51+
- "statefulsets"
52+
verbs: ["*"]
4953
- apiGroups: [""]
5054
resources:
5155
- "pods"
5256
- "secrets"
57+
- "services"
5358
- "serviceaccounts"
5459
verbs: ["*"]
5560
{{- end }}

pkg/apis/ml/v1alpha1/extension_conditions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const (
2828
ExtensionBootstrapCompletedCondition api.ConditionType = "BootstrapCompleted"
2929
ExtensionMetadataServiceValidCondition api.ConditionType = "MetadataServiceValid"
3030
ExtensionServiceAccountReadyCondition api.ConditionType = "ServiceAccountReady"
31+
ExtensionStatefulSetReadyCondition api.ConditionType = "ExtensionDeploymentReady"
3132
LicenseValidCondition api.ConditionType = "LicenseValid"
3233
CronJobSyncedCondition api.ConditionType = "CronJobSynced"
3334
)

pkg/handlers/backup/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func (h *handler) getDeploymentMutex(namespace, deployment string) *sync.Mutex {
207207
}
208208

209209
func (h *handler) Handle(_ context.Context, item operation.Item) error {
210-
// Get Backup object. It also covers NotFound case
210+
// Get object. It also covers NotFound case
211211
b, err := h.client.BackupV1().ArangoBackups(item.Namespace).Get(context.Background(), item.Name, meta.GetOptions{})
212212
if err != nil {
213213
if apiErrors.IsNotFound(err) {

pkg/handlers/policy/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (h *handler) Handle(_ context.Context, item operation.Item) error {
7070
return nil
7171
}
7272

73-
// Get Backup object. It also cover NotFound case
73+
// Get object. It also cover NotFound case
7474
policy, err := h.client.BackupV1().ArangoBackupPolicies(item.Namespace).Get(context.Background(), item.Name, meta.GetOptions{})
7575
if err != nil {
7676
return err

pkg/license/license.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package license
2222

2323
import (
2424
"context"
25+
"strconv"
2526
)
2627

2728
type Status int
@@ -67,6 +68,28 @@ func (s Status) Valid() bool {
6768
func (s Status) Validate(feature Feature, subFeatures ...Feature) Status {
6869
return s
6970
}
71+
func (s Status) String() string {
72+
switch s {
73+
case StatusMissing:
74+
return "Missing"
75+
case StatusInvalid:
76+
return "Invalid"
77+
case StatusInvalidSignature:
78+
return "InvalidSignature"
79+
case StatusNotYetValid:
80+
return "NotYetValid"
81+
case StatusNotAnymoreValid:
82+
return "NotAnymoreValid"
83+
case StatusFeatureNotEnabled:
84+
return "FeatureNotEnabled"
85+
case StatusFeatureExpired:
86+
return "FeatureExpired"
87+
case StatusValid:
88+
return "Valid"
89+
default:
90+
return strconv.Itoa(int(s))
91+
}
92+
}
7093

7194
type Feature string
7295

pkg/util/helpers.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package util
22+
23+
// Ter implements a ternary operation: return cond ? a : b;
24+
func Ter[T any](cond bool, a T, b T) T {
25+
if cond {
26+
return a
27+
}
28+
return b
29+
}

pkg/util/k8sutil/security_context.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import (
2424
core "k8s.io/api/core/v1"
2525

2626
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
27+
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
2728
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
29+
"github.com/arangodb/kube-arangodb/pkg/util"
2830
)
2931

3032
// CreateSecurityContext returns security context.
@@ -37,3 +39,29 @@ func CreateSecurityContext(spec *api.ServerGroupSpecSecurityContext) *core.Secur
3739
func CreatePodSecurityContext(spec *api.ServerGroupSpecSecurityContext) *core.PodSecurityContext {
3840
return spec.NewPodSecurityContext(features.SecuredContainers().Enabled())
3941
}
42+
43+
func CreateSecurePodSecurityContext() *core.PodSecurityContext {
44+
psc := &core.PodSecurityContext{
45+
RunAsUser: util.NewType[int64](shared.DefaultRunAsUser),
46+
RunAsGroup: util.NewType[int64](shared.DefaultRunAsGroup),
47+
RunAsNonRoot: util.NewType(true),
48+
FSGroup: util.NewType[int64](shared.DefaultFSGroup),
49+
}
50+
51+
return psc
52+
}
53+
54+
func CreateDefaultSecurityContext() *core.SecurityContext {
55+
r := &core.SecurityContext{
56+
RunAsUser: util.NewType[int64](shared.DefaultRunAsUser),
57+
RunAsGroup: util.NewType[int64](shared.DefaultRunAsGroup),
58+
RunAsNonRoot: util.NewType(true),
59+
ReadOnlyRootFilesystem: util.NewType(true),
60+
Capabilities: &core.Capabilities{
61+
Drop: []core.Capability{
62+
"ALL",
63+
},
64+
},
65+
}
66+
return r
67+
}

pkg/util/k8sutil/util.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -50,8 +50,12 @@ const (
5050
LabelKeyArangoActive = "deployment.arangodb.com/active"
5151
// LabelValueArangoActive is the value of the label used to mark members as active.
5252
LabelValueArangoActive = "true"
53-
// AppName is the fixed value for the "app" label
53+
// LabelKeyArangoMLStatefulSet is the key of the label used to define k8s StatefulSet for ML Extension
54+
LabelKeyArangoMLStatefulSet = "ml.arangodb.com/statefulset"
55+
// AppName is the value for the "app" label
5456
AppName = "arangodb"
57+
// AppArangoML is the value for the "app" label
58+
AppArangoML = "arangoml"
5559
)
5660

5761
// AddOwnerRefToObject adds given owner reference to given object

pkg/util/tests/kubernetes.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"testing"
2828

2929
"github.com/stretchr/testify/require"
30+
apps "k8s.io/api/apps/v1"
3031
batch "k8s.io/api/batch/v1"
3132
core "k8s.io/api/core/v1"
3233
rbac "k8s.io/api/rbac/v1"
@@ -120,12 +121,24 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
120121
vl := *v
121122
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
122123
require.NoError(t, err)
124+
case **core.Service:
125+
require.NotNil(t, v)
126+
127+
vl := *v
128+
_, err := k8s.CoreV1().Services(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
129+
require.NoError(t, err)
123130
case **core.ServiceAccount:
124131
require.NotNil(t, v)
125132

126133
vl := *v
127134
_, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
128135
require.NoError(t, err)
136+
case **apps.StatefulSet:
137+
require.NotNil(t, v)
138+
139+
vl := *v
140+
_, err := k8s.AppsV1().StatefulSets(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
141+
require.NoError(t, err)
129142
case **api.ArangoDeployment:
130143
require.NotNil(t, v)
131144

@@ -223,12 +236,23 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
223236
vl := *v
224237
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
225238
require.NoError(t, err)
239+
case **core.Service:
240+
require.NotNil(t, v)
241+
242+
vl := *v
243+
_, err := k8s.CoreV1().Services(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
244+
require.NoError(t, err)
226245
case **core.ServiceAccount:
227246
require.NotNil(t, v)
228247

229248
vl := *v
230249
_, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
231250
require.NoError(t, err)
251+
case **apps.StatefulSet:
252+
require.NotNil(t, v)
253+
vl := *v
254+
_, err := k8s.AppsV1().StatefulSets(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
255+
require.NoError(t, err)
232256
case **api.ArangoDeployment:
233257
require.NotNil(t, v)
234258

@@ -450,6 +474,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
450474
} else {
451475
*v = vn
452476
}
477+
case **core.Service:
478+
require.NotNil(t, v)
479+
480+
vl := *v
481+
482+
vn, err := k8s.CoreV1().Services(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
483+
if err != nil {
484+
if kerrors.IsNotFound(err) {
485+
*v = nil
486+
} else {
487+
require.NoError(t, err)
488+
}
489+
} else {
490+
*v = vn
491+
}
453492
case **core.ServiceAccount:
454493
require.NotNil(t, v)
455494

@@ -465,6 +504,20 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
465504
} else {
466505
*v = vn
467506
}
507+
case **apps.StatefulSet:
508+
require.NotNil(t, v)
509+
510+
vl := *v
511+
vn, err := k8s.AppsV1().StatefulSets(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
512+
if err != nil {
513+
if kerrors.IsNotFound(err) {
514+
*v = nil
515+
} else {
516+
require.NoError(t, err)
517+
}
518+
} else {
519+
*v = vn
520+
}
468521
case **api.ArangoDeployment:
469522
require.NotNil(t, v)
470523

@@ -616,7 +669,7 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
616669
*v = vn
617670
}
618671
default:
619-
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
672+
require.Fail(t, fmt.Sprintf("Unable to get object: %s", reflect.TypeOf(v).String()))
620673
}
621674
}
622675
}
@@ -649,12 +702,24 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
649702
v.SetSelfLink(fmt.Sprintf("/api/v1/secrets/%s/%s",
650703
object.GetNamespace(),
651704
object.GetName()))
705+
case *core.Service:
706+
v.Kind = "Service"
707+
v.APIVersion = "v1"
708+
v.SetSelfLink(fmt.Sprintf("/api/v1/services/%s/%s",
709+
object.GetNamespace(),
710+
object.GetName()))
652711
case *core.ServiceAccount:
653712
v.Kind = "ServiceAccount"
654713
v.APIVersion = "v1"
655714
v.SetSelfLink(fmt.Sprintf("/api/v1/serviceaccounts/%s/%s",
656715
object.GetNamespace(),
657716
object.GetName()))
717+
case *apps.StatefulSet:
718+
v.Kind = "StatefulSet"
719+
v.APIVersion = "v1"
720+
v.SetSelfLink(fmt.Sprintf("/api/apps/v1/statefulsets/%s/%s",
721+
object.GetNamespace(),
722+
object.GetName()))
658723
case *api.ArangoDeployment:
659724
v.Kind = deployment.ArangoDeploymentResourceKind
660725
v.APIVersion = api.SchemeGroupVersion.String()
@@ -790,10 +855,18 @@ func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.
790855
item.Group = ""
791856
item.Version = "v1"
792857
item.Kind = "Secret"
858+
case *core.Service:
859+
item.Group = ""
860+
item.Version = "v1"
861+
item.Kind = "Service"
793862
case *core.ServiceAccount:
794863
item.Group = ""
795864
item.Version = "v1"
796865
item.Kind = "ServiceAccount"
866+
case *apps.StatefulSet:
867+
item.Group = "apps"
868+
item.Version = "v1"
869+
item.Kind = "StatefulSet"
797870
case *api.ArangoDeployment:
798871
item.Group = deployment.ArangoDeploymentGroupName
799872
item.Version = api.ArangoDeploymentVersion

0 commit comments

Comments
 (0)