Skip to content

Commit 846b621

Browse files
authored
[Feature] [Integration] SchedulerV2 (#1744)
1 parent ac0a256 commit 846b621

File tree

16 files changed

+1169
-3
lines changed

16 files changed

+1169
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- (Feature) Helm Client Extension
77
- (Feature) (Integration) SchedulerV2 Definition
88
- (Maintenance) Proto Lint
9+
- (Feature) (Integration) SchedulerV2
910

1011
## [1.2.43](https://github.com/arangodb/kube-arangodb/tree/1.2.43) (2024-10-14)
1112
- (Feature) ArangoRoute CRD
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2024 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 v2
22+
23+
import "github.com/pkg/errors"
24+
25+
type Mod func(c Configuration) Configuration
26+
27+
func NewConfiguration() Configuration {
28+
return Configuration{
29+
Namespace: "default",
30+
}
31+
}
32+
33+
type Configuration struct {
34+
Namespace string
35+
36+
Deployment string
37+
}
38+
39+
func (c Configuration) Validate() error {
40+
if c.Deployment == "" {
41+
return errors.Errorf("Invalid empty name of deployment")
42+
}
43+
44+
if c.Namespace == "" {
45+
return errors.Errorf("Invalid empty name of namespace")
46+
}
47+
48+
return nil
49+
}
50+
51+
func (c Configuration) With(mods ...Mod) Configuration {
52+
n := c
53+
54+
for _, mod := range mods {
55+
n = mod(n)
56+
}
57+
58+
return n
59+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2024 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 v2
22+
23+
const (
24+
LabelArangoDBDeploymentName = "deployment.arangodb.com/name"
25+
)

integrations/scheduler/v2/helm.go

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2024 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 v2
22+
23+
import (
24+
"context"
25+
26+
"google.golang.org/grpc/codes"
27+
"google.golang.org/grpc/status"
28+
"helm.sh/helm/v3/pkg/action"
29+
"k8s.io/apimachinery/pkg/labels"
30+
"k8s.io/apimachinery/pkg/selection"
31+
32+
pbSchedulerV2 "github.com/arangodb/kube-arangodb/integrations/scheduler/v2/definition"
33+
pbSharedV1 "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
34+
"github.com/arangodb/kube-arangodb/pkg/util"
35+
)
36+
37+
func (i *implementation) Alive(ctx context.Context, in *pbSharedV1.Empty) (*pbSharedV1.Empty, error) {
38+
if err := i.client.Alive(ctx); err != nil {
39+
logger.Err(err).Warn("Helm is not alive")
40+
return nil, status.Errorf(codes.Unavailable, "Service is not alive")
41+
}
42+
43+
return &pbSharedV1.Empty{}, nil
44+
}
45+
46+
func (i *implementation) List(ctx context.Context, in *pbSchedulerV2.SchedulerV2ListRequest) (*pbSchedulerV2.SchedulerV2ListResponse, error) {
47+
var mods []util.Mod[action.List]
48+
49+
mods = append(mods, in.GetOptions().Options()...)
50+
mods = append(mods, func(action *action.List) {
51+
var s = labels.NewSelector()
52+
if action.Selector != "" {
53+
if n, err := labels.Parse(action.Selector); err == nil {
54+
s = n
55+
}
56+
}
57+
58+
if r, err := labels.NewRequirement(LabelArangoDBDeploymentName, selection.DoubleEquals, []string{i.cfg.Deployment}); err != nil {
59+
logger.Err(err).Warn("Unable to render selector")
60+
} else if r != nil {
61+
s = s.Add(*r)
62+
}
63+
64+
action.Selector = s.String()
65+
})
66+
67+
resp, err := i.client.List(ctx, mods...)
68+
if err != nil {
69+
logger.Err(err).Warn("Unable to run action: List")
70+
return nil, status.Errorf(codes.Internal, "Unable to run action: List: %s", err.Error())
71+
}
72+
73+
releases := make(map[string]*pbSchedulerV2.SchedulerV2Release, len(resp))
74+
75+
for _, r := range resp {
76+
releases[r.Name] = newChartReleaseFromHelmRelease(&r)
77+
}
78+
79+
return &pbSchedulerV2.SchedulerV2ListResponse{
80+
Releases: releases,
81+
}, nil
82+
}
83+
84+
func (i *implementation) Status(ctx context.Context, in *pbSchedulerV2.SchedulerV2StatusRequest) (*pbSchedulerV2.SchedulerV2StatusResponse, error) {
85+
if in.GetName() == "" {
86+
return nil, status.Errorf(codes.InvalidArgument, "Name cannot be empty")
87+
}
88+
89+
resp, err := i.client.Status(ctx, in.GetName())
90+
if err != nil {
91+
logger.Err(err).Warn("Unable to run action: Status")
92+
return nil, status.Errorf(codes.Internal, "Unable to run action: Status: %s", err.Error())
93+
}
94+
95+
return &pbSchedulerV2.SchedulerV2StatusResponse{
96+
Release: newChartReleaseFromHelmRelease(resp),
97+
}, nil
98+
}
99+
func (i *implementation) StatusObjects(ctx context.Context, in *pbSchedulerV2.SchedulerV2StatusObjectsRequest) (*pbSchedulerV2.SchedulerV2StatusObjectsResponse, error) {
100+
if in.GetName() == "" {
101+
return nil, status.Errorf(codes.InvalidArgument, "Name cannot be empty")
102+
}
103+
104+
resp, objs, err := i.client.StatusObjects(ctx, in.GetName())
105+
if err != nil {
106+
logger.Err(err).Warn("Unable to run action: Status")
107+
return nil, status.Errorf(codes.Internal, "Unable to run action: Status: %s", err.Error())
108+
}
109+
110+
return &pbSchedulerV2.SchedulerV2StatusObjectsResponse{
111+
Release: newChartReleaseFromHelmRelease(resp),
112+
Objects: newReleaseInfoResourceObjectsFromResourceObjects(objs),
113+
}, nil
114+
}
115+
116+
func (i *implementation) Install(ctx context.Context, in *pbSchedulerV2.SchedulerV2InstallRequest) (*pbSchedulerV2.SchedulerV2InstallResponse, error) {
117+
if in.GetName() == "" {
118+
return nil, status.Errorf(codes.InvalidArgument, "Name cannot be empty")
119+
}
120+
121+
var mods []util.Mod[action.Install]
122+
123+
mods = append(mods, in.GetOptions().Options()...)
124+
mods = append(mods, func(action *action.Install) {
125+
action.ReleaseName = in.GetName()
126+
action.Namespace = i.cfg.Namespace
127+
128+
if action.Labels == nil {
129+
action.Labels = map[string]string{}
130+
}
131+
132+
action.Labels[LabelArangoDBDeploymentName] = i.cfg.Deployment
133+
})
134+
135+
resp, err := i.client.Install(ctx, in.GetChart(), in.GetValues(), mods...)
136+
if err != nil {
137+
logger.Err(err).Warn("Unable to run action: Install")
138+
return nil, status.Errorf(codes.Internal, "Unable to run action: Install: %s", err.Error())
139+
}
140+
141+
return &pbSchedulerV2.SchedulerV2InstallResponse{
142+
Release: newChartReleaseFromHelmRelease(resp),
143+
}, nil
144+
}
145+
146+
func (i *implementation) Upgrade(ctx context.Context, in *pbSchedulerV2.SchedulerV2UpgradeRequest) (*pbSchedulerV2.SchedulerV2UpgradeResponse, error) {
147+
if in.GetName() == "" {
148+
return nil, status.Errorf(codes.InvalidArgument, "Name cannot be empty")
149+
}
150+
151+
var mods []util.Mod[action.Upgrade]
152+
153+
mods = append(mods, in.GetOptions().Options()...)
154+
mods = append(mods, func(action *action.Upgrade) {
155+
action.Namespace = i.cfg.Namespace
156+
157+
if action.Labels == nil {
158+
action.Labels = map[string]string{}
159+
}
160+
161+
action.Labels[LabelArangoDBDeploymentName] = i.cfg.Deployment
162+
})
163+
164+
resp, err := i.client.Upgrade(ctx, in.GetName(), in.GetChart(), in.GetValues(), mods...)
165+
if err != nil {
166+
logger.Err(err).Warn("Unable to run action: Upgrade")
167+
return nil, status.Errorf(codes.Internal, "Unable to run action: Upgrade: %s", err.Error())
168+
}
169+
170+
var r pbSchedulerV2.SchedulerV2UpgradeResponse
171+
172+
if q := resp.Before; q != nil {
173+
r.Before = newChartReleaseFromHelmRelease(q)
174+
}
175+
176+
if q := resp.After; q != nil {
177+
r.After = newChartReleaseFromHelmRelease(q)
178+
}
179+
180+
return &r, nil
181+
}
182+
183+
func (i *implementation) Uninstall(ctx context.Context, in *pbSchedulerV2.SchedulerV2UninstallRequest) (*pbSchedulerV2.SchedulerV2UninstallResponse, error) {
184+
if in.GetName() == "" {
185+
return nil, status.Errorf(codes.InvalidArgument, "Name cannot be empty")
186+
}
187+
188+
var mods []util.Mod[action.Uninstall]
189+
190+
mods = append(mods, in.GetOptions().Options()...)
191+
192+
resp, err := i.client.Uninstall(ctx, in.GetName(), mods...)
193+
if err != nil {
194+
logger.Err(err).Warn("Unable to run action: Uninstall")
195+
return nil, status.Errorf(codes.Internal, "Unable to run action: Uninstall: %s", err.Error())
196+
}
197+
198+
return &pbSchedulerV2.SchedulerV2UninstallResponse{
199+
Info: resp.Info,
200+
Release: newChartReleaseFromHelmRelease(&resp.Release),
201+
}, nil
202+
}
203+
204+
func (i *implementation) Test(ctx context.Context, in *pbSchedulerV2.SchedulerV2TestRequest) (*pbSchedulerV2.SchedulerV2TestResponse, error) {
205+
if in.GetName() == "" {
206+
return nil, status.Errorf(codes.InvalidArgument, "Name cannot be empty")
207+
}
208+
209+
var mods []util.Mod[action.ReleaseTesting]
210+
211+
mods = append(mods, in.GetOptions().Options()...)
212+
213+
resp, err := i.client.Test(ctx, in.GetName(), mods...)
214+
if err != nil {
215+
logger.Err(err).Warn("Unable to run action: Test")
216+
return nil, status.Errorf(codes.Internal, "Unable to run action: Test: %s", err.Error())
217+
}
218+
219+
return &pbSchedulerV2.SchedulerV2TestResponse{
220+
Release: newChartReleaseFromHelmRelease(resp),
221+
}, nil
222+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2024 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 v2
22+
23+
import (
24+
"context"
25+
26+
"google.golang.org/grpc"
27+
28+
pbSchedulerV2 "github.com/arangodb/kube-arangodb/integrations/scheduler/v2/definition"
29+
pbSharedV1 "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
30+
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/helm"
31+
"github.com/arangodb/kube-arangodb/pkg/util/svc"
32+
)
33+
34+
var _ pbSchedulerV2.SchedulerV2Server = &implementation{}
35+
var _ svc.Handler = &implementation{}
36+
37+
func New(client helm.Client, cfg Configuration) (svc.Handler, error) {
38+
return newInternal(client, cfg)
39+
}
40+
41+
func newInternal(client helm.Client, c Configuration) (*implementation, error) {
42+
if err := c.Validate(); err != nil {
43+
return nil, err
44+
}
45+
46+
return &implementation{
47+
cfg: c,
48+
client: client,
49+
}, nil
50+
}
51+
52+
type implementation struct {
53+
cfg Configuration
54+
55+
client helm.Client
56+
57+
pbSchedulerV2.UnimplementedSchedulerV2Server
58+
}
59+
60+
func (i *implementation) Name() string {
61+
return pbSchedulerV2.Name
62+
}
63+
64+
func (i *implementation) Register(registrar *grpc.Server) {
65+
pbSchedulerV2.RegisterSchedulerV2Server(registrar, i)
66+
}
67+
68+
func (i *implementation) Health() svc.HealthState {
69+
return svc.Healthy
70+
}
71+
72+
func (i *implementation) InvalidateCache(ctx context.Context, in *pbSharedV1.Empty) (*pbSharedV1.Empty, error) {
73+
i.client.Invalidate()
74+
75+
return &pbSharedV1.Empty{}, nil
76+
}

0 commit comments

Comments
 (0)