Skip to content

Commit 0703b9a

Browse files
AleksZiminastef
andauthored
[controller] Add node selectors for workload nodes (#58)
Signed-off-by: Aleksandr Zimin <[email protected]> Signed-off-by: Aleksandr Stefurishin <[email protected]> Co-authored-by: Aleksandr Stefurishin <[email protected]>
1 parent 6525b9a commit 0703b9a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+4155
-124
lines changed

.golangci.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ linters-settings:
1313
sections:
1414
- standard
1515
- default
16+
- prefix(d8-controller)
17+
- prefix(csi-nfs-scheduler-extender)
18+
- prefix(webhooks)
1619

1720
linters:
1821
disable-all: true

api/v1alpha1/nfs_storage_class.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ type NFSStorageClassList struct {
3939

4040
// +k8s:deepcopy-gen=true
4141
type NFSStorageClassSpec struct {
42-
Connection *NFSStorageClassConnection `json:"connection,omitempty"`
43-
MountOptions *NFSStorageClassMountOptions `json:"mountOptions,omitempty"`
44-
ChmodPermissions string `json:"chmodPermissions,omitempty"`
45-
ReclaimPolicy string `json:"reclaimPolicy"`
46-
VolumeBindingMode string `json:"volumeBindingMode"`
42+
Connection *NFSStorageClassConnection `json:"connection,omitempty"`
43+
MountOptions *NFSStorageClassMountOptions `json:"mountOptions,omitempty"`
44+
ChmodPermissions string `json:"chmodPermissions,omitempty"`
45+
ReclaimPolicy string `json:"reclaimPolicy"`
46+
VolumeBindingMode string `json:"volumeBindingMode"`
47+
WorkloadNodes *NFSStorageClassWorkloadNodes `json:"workloadNodes,omitempty"`
4748
}
4849

4950
// +k8s:deepcopy-gen=true
@@ -61,6 +62,11 @@ type NFSStorageClassMountOptions struct {
6162
ReadOnly *bool `json:"readOnly,omitempty"`
6263
}
6364

65+
// +k8s:deepcopy-gen=true
66+
type NFSStorageClassWorkloadNodes struct {
67+
NodeSelector *metav1.LabelSelector `json:"nodeSelector"`
68+
}
69+
6470
// +k8s:deepcopy-gen=true
6571
type NFSStorageClassStatus struct {
6672
Phase string `json:"phase,omitempty"`

crds/doc-ru-nfsstorageclass.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ spec:
5050
volumeBindingMode:
5151
description: |
5252
Режим создания тома. Может быть Immediate (запрос при создании PVC) или WaitForFirstConsumer (до появления первого Pod)
53+
nodeSelector:
54+
description: |
55+
Селектор узлов для определения правил выбора узлов, на которых Persistent Volumes (PVs), созданные этим StorageClass, могут подключаться. Комбинирует простое сопоставление меток и сложные выражения для фильтрации узлов.
56+
properties:
57+
matchLabels:
58+
description: |
59+
Карта меток, которые должны точно совпадать с метками узла. Узлы, которые не соответствуют хотя бы одной из указанных меток, будут исключены.
60+
matchExpressions:
61+
description: |
62+
Список сложных условий выбора узлов. Каждое условие задаёт ключ, оператор и, при необходимости, значения для фильтрации узлов на основе их меток или других полей.
5363
status:
5464
properties:
5565
phase:

crds/nfsstorageclass.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,43 @@ spec:
129129
enum:
130130
- Immediate
131131
- WaitForFirstConsumer
132+
workloadNodes:
133+
type: object
134+
minProperties: 1
135+
properties:
136+
nodeSelector:
137+
type: object
138+
minProperties: 1
139+
description: |
140+
Node selector to specify rules for selecting nodes where Persistent Volumes (PVs) created by this StorageClass are allowed to connect. Combines simple label matches and advanced matching expressions.
141+
If this parameter is omitted, NFS shares can be mounted on any node in the cluster running the `Linux` OS.
142+
properties:
143+
matchLabels:
144+
type: object
145+
description: |
146+
A map of labels that must match exactly with the labels of a node. Nodes that do not match any of the specified labels will be excluded.
147+
additionalProperties:
148+
type: string
149+
matchExpressions:
150+
type: array
151+
description: |
152+
A list of advanced node selector requirements. Each requirement specifies a key, an operator, and optional values for filtering nodes based on their labels or other fields.
153+
items:
154+
type: object
155+
properties:
156+
key:
157+
type: string
158+
operator:
159+
type: string
160+
enum:
161+
- In
162+
- NotIn
163+
- Exists
164+
- DoesNotExist
165+
values:
166+
type: array
167+
items:
168+
type: string
132169
status:
133170
type: object
134171
description: |
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright 2023 Flant JSC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
from lib.hooks.internal_tls import GenerateCertificateHook, TlsSecret, default_sans
19+
from lib.module import values as module_values
20+
from deckhouse import hook
21+
from typing import Callable
22+
import common
23+
24+
def main():
25+
hook = GenerateCertificateHook(
26+
TlsSecret(
27+
cn="csi-nfs-scheduler-extender",
28+
name="scheduler-extender-https-certs",
29+
sansGenerator=default_sans([
30+
"csi-nfs-scheduler-extender",
31+
f"csi-nfs-scheduler-extender.{common.NAMESPACE}",
32+
f"csi-nfs-scheduler-extender.{common.NAMESPACE}.svc",
33+
f"%CLUSTER_DOMAIN%://csi-nfs-scheduler-extender.{common.NAMESPACE}.svc",
34+
]),
35+
values_path_prefix=f"{common.MODULE_NAME}.internal.customSchedulerExtenderCert"
36+
),
37+
cn="csi-nfs-scheduler-extender",
38+
common_ca=True,
39+
namespace=common.NAMESPACE)
40+
41+
hook.run()
42+
43+
if __name__ == "__main__":
44+
main()
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright 2025 Flant JSC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
# import yaml
19+
# from deckhouse import hook
20+
from deckhouse import hook
21+
22+
from lib.hooks.hook import Hook
23+
from lib.module import values as module_values
24+
25+
26+
config = """
27+
configVersion: v1
28+
kubernetes:
29+
- name: nfs-storage-classes
30+
apiVersion: storage.deckhouse.io/v1alpha1
31+
kind: NFSStorageClass
32+
includeSnapshotsFrom:
33+
- nfs-storage-classes
34+
executeHookOnEvent: [ "Added", "Modified", "Deleted" ]
35+
executeHookOnSynchronization: true
36+
keepFullObjectsInMemory: false
37+
jqFilter: ".spec.workloadNodes"
38+
queue: /modules/csi-nfs
39+
settings:
40+
executionMinInterval: 3s
41+
executionBurst: 1
42+
"""
43+
44+
def main(ctx: hook.Context):
45+
print("Scheduler extender enabler hook started")
46+
should_enable = False
47+
snapshots = ctx.snapshots.get("nfs-storage-classes", [])
48+
for snapshot in snapshots:
49+
print(f"get snapshot: {snapshot}")
50+
filter_result = snapshot.get("filterResult", [])
51+
if not filter_result:
52+
print(f"filter result is empty")
53+
continue
54+
print(f"get filter result: {filter_result}")
55+
nodeSelector = filter_result.get("nodeSelector", {})
56+
print(f"get nodeSelector: {nodeSelector}")
57+
if not nodeSelector:
58+
print(f"nodeSelector is empty")
59+
continue
60+
print("NodeSelector is not empty. Should enable scheduler extender")
61+
should_enable = True
62+
break
63+
if should_enable:
64+
print("Enable scheduler extender")
65+
module_values.set_value(f"csiNfs.internal.shedulerExtenderEnabled", ctx.values, True)
66+
else:
67+
print("Disable scheduler extender")
68+
module_values.set_value(f"csiNfs.internal.shedulerExtenderEnabled", ctx.values, False)
69+
70+
71+
if __name__ == "__main__":
72+
hook.run(main, config=config)

images/controller/src/cmd/main.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ import (
2222
"os"
2323
goruntime "runtime"
2424

25-
"d8-controller/pkg/config"
26-
"d8-controller/pkg/controller"
27-
"d8-controller/pkg/kubutils"
28-
"d8-controller/pkg/logger"
2925
cn "github.com/deckhouse/csi-nfs/api/v1alpha1"
26+
snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
3027
v1 "k8s.io/api/core/v1"
3128
sv1 "k8s.io/api/storage/v1"
3229
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -36,6 +33,11 @@ import (
3633
"sigs.k8s.io/controller-runtime/pkg/cache"
3734
"sigs.k8s.io/controller-runtime/pkg/healthz"
3835
"sigs.k8s.io/controller-runtime/pkg/manager"
36+
37+
"d8-controller/pkg/config"
38+
"d8-controller/pkg/controller"
39+
"d8-controller/pkg/kubutils"
40+
"d8-controller/pkg/logger"
3941
)
4042

4143
var (
@@ -45,6 +47,7 @@ var (
4547
extv1.AddToScheme,
4648
v1.AddToScheme,
4749
sv1.AddToScheme,
50+
snapshotv1.AddToScheme,
4851
}
4952
)
5053

@@ -110,6 +113,8 @@ func main() {
110113
os.Exit(1)
111114
}
112115

116+
controller.RunNodeSelectorReconciler(ctx, mgr, *cfgParams, *log)
117+
113118
if err = mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
114119
log.Error(err, "[main] unable to mgr.AddHealthzCheck")
115120
os.Exit(1)

images/controller/src/go.mod

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ go 1.23.4
55
require (
66
github.com/deckhouse/csi-nfs/api v0.0.0-20250116103144-d23aedd591a3
77
github.com/go-logr/logr v1.4.2
8+
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0
89
github.com/onsi/ginkgo/v2 v2.22.2
910
github.com/onsi/gomega v1.36.2
10-
k8s.io/api v0.32.0
11-
k8s.io/apiextensions-apiserver v0.32.0
12-
k8s.io/apimachinery v0.32.0
13-
k8s.io/client-go v0.32.0
11+
gopkg.in/yaml.v3 v3.0.1
12+
k8s.io/api v0.32.1
13+
k8s.io/apiextensions-apiserver v0.32.1
14+
k8s.io/apimachinery v0.32.1
15+
k8s.io/client-go v0.32.1
1416
k8s.io/klog/v2 v2.130.1
15-
sigs.k8s.io/controller-runtime v0.19.4
17+
sigs.k8s.io/controller-runtime v0.20.0
1618
)
1719

1820
replace github.com/deckhouse/csi-nfs/api => ../../../api
@@ -31,6 +33,7 @@ require (
3133
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
3234
github.com/gogo/protobuf v1.3.2 // indirect
3335
github.com/golang/protobuf v1.5.4 // indirect
36+
github.com/google/btree v1.1.3 // indirect
3437
github.com/google/gnostic-models v0.6.9 // indirect
3538
github.com/google/go-cmp v0.6.0 // indirect
3639
github.com/google/gofuzz v1.2.0 // indirect
@@ -46,23 +49,22 @@ require (
4649
github.com/pkg/errors v0.9.1 // indirect
4750
github.com/prometheus/client_golang v1.20.5 // indirect
4851
github.com/prometheus/client_model v0.6.1 // indirect
49-
github.com/prometheus/common v0.61.0 // indirect
52+
github.com/prometheus/common v0.62.0 // indirect
5053
github.com/prometheus/procfs v0.15.1 // indirect
5154
github.com/spf13/pflag v1.0.5 // indirect
5255
github.com/x448/float16 v0.8.4 // indirect
53-
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
5456
golang.org/x/net v0.34.0 // indirect
5557
golang.org/x/oauth2 v0.25.0 // indirect
58+
golang.org/x/sync v0.10.0 // indirect
5659
golang.org/x/sys v0.29.0 // indirect
5760
golang.org/x/term v0.28.0 // indirect
5861
golang.org/x/text v0.21.0 // indirect
5962
golang.org/x/time v0.9.0 // indirect
6063
golang.org/x/tools v0.29.0 // indirect
6164
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
62-
google.golang.org/protobuf v1.36.2 // indirect
65+
google.golang.org/protobuf v1.36.3 // indirect
6366
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
6467
gopkg.in/inf.v0 v0.9.1 // indirect
65-
gopkg.in/yaml.v3 v3.0.1 // indirect
6668
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
6769
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
6870
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect

0 commit comments

Comments
 (0)