@@ -3,18 +3,20 @@ package v1alpha1
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "math/rand"
6
7
7
8
"github.com/google/go-cmp/cmp"
8
9
"github.com/google/go-cmp/cmp/cmpopts"
9
10
"gopkg.in/yaml.v3"
10
- v1 "k8s.io/api/core/v1"
11
+ corev1 "k8s.io/api/core/v1"
11
12
"k8s.io/apimachinery/pkg/runtime"
12
13
"k8s.io/utils/strings/slices"
13
14
ctrl "sigs.k8s.io/controller-runtime"
14
15
"sigs.k8s.io/controller-runtime/pkg/client"
15
16
logf "sigs.k8s.io/controller-runtime/pkg/log"
16
17
"sigs.k8s.io/controller-runtime/pkg/webhook"
17
18
19
+ "github.com/ydb-platform/ydb-kubernetes-operator/internal/configuration/schema"
18
20
. "github.com/ydb-platform/ydb-kubernetes-operator/internal/controllers/constants" //nolint:revive,stylecheck
19
21
)
20
22
@@ -29,15 +31,28 @@ func (r *Storage) SetupWebhookWithManager(mgr ctrl.Manager) error {
29
31
}
30
32
31
33
func (r * Storage ) GetStorageEndpointWithProto () string {
34
+ return fmt .Sprintf ("%s%s" , r .GetStorageProto (), r .GetStorageEndpoint ())
35
+ }
36
+
37
+ func (r * Storage ) GetStorageProto () string {
32
38
proto := GRPCProto
33
39
if r .IsStorageEndpointSecure () {
34
40
proto = GRPCSProto
35
41
}
36
42
37
- return fmt . Sprintf ( "%s%s" , proto , r . GetStorageEndpoint ())
43
+ return proto
38
44
}
39
45
40
46
func (r * Storage ) GetStorageEndpoint () string {
47
+ endpoint := r .GetGRPCServiceEndpoint ()
48
+ if r .IsRemoteNodeSetsOnly () {
49
+ endpoint = r .GetHostFromConfigEndpoint ()
50
+ }
51
+
52
+ return endpoint
53
+ }
54
+
55
+ func (r * Storage ) GetGRPCServiceEndpoint () string {
41
56
host := fmt .Sprintf (GRPCServiceFQDNFormat , r .Name , r .Namespace )
42
57
if r .Spec .Service .GRPC .ExternalHost != "" {
43
58
host = r .Spec .Service .GRPC .ExternalHost
@@ -46,15 +61,44 @@ func (r *Storage) GetStorageEndpoint() string {
46
61
return fmt .Sprintf ("%s:%d" , host , GRPCPort )
47
62
}
48
63
64
+ // +k8s:deepcopy-gen=false
65
+ type PartialHostsConfig struct {
66
+ Hosts []schema.Host `yaml:"hosts,flow"`
67
+ }
68
+
69
+ func (r * Storage ) GetHostFromConfigEndpoint () string {
70
+ // skip handle error because we already checked in webhook
71
+ hostsConfig := PartialHostsConfig {}
72
+ _ = yaml .Unmarshal ([]byte (r .Spec .Configuration ), & hostsConfig )
73
+
74
+ randNum := rand .Int31n (r .Spec .Nodes ) // #nosec G404
75
+ host := hostsConfig .Hosts [randNum ].Host
76
+ return fmt .Sprintf ("%s:%d" , host , GRPCPort )
77
+ }
78
+
49
79
func (r * Storage ) IsStorageEndpointSecure () bool {
50
80
if r .Spec .Service .GRPC .TLSConfiguration != nil {
51
81
return r .Spec .Service .GRPC .TLSConfiguration .Enabled
52
82
}
53
83
return false
54
84
}
55
85
86
+ func (r * Storage ) IsRemoteNodeSetsOnly () bool {
87
+ if len (r .Spec .NodeSets ) == 0 {
88
+ return false
89
+ }
90
+
91
+ for _ , nodeSet := range r .Spec .NodeSets {
92
+ if nodeSet .Remote == nil {
93
+ return false
94
+ }
95
+ }
96
+
97
+ return true
98
+ }
99
+
56
100
// +k8s:deepcopy-gen=false
57
- type PartialYamlConfig struct {
101
+ type PartialDomainsConfig struct {
58
102
DomainsConfig struct {
59
103
SecurityConfig struct {
60
104
EnforceUserTokenRequirement bool `yaml:"enforce_user_token_requirement"`
@@ -88,12 +132,12 @@ func (r *StorageDefaulter) Default(ctx context.Context, obj runtime.Object) erro
88
132
}
89
133
90
134
if storage .Spec .Image .PullPolicyName == nil {
91
- policy := v1 .PullIfNotPresent
135
+ policy := corev1 .PullIfNotPresent
92
136
storage .Spec .Image .PullPolicyName = & policy
93
137
}
94
138
95
139
if storage .Spec .Resources == nil {
96
- storage .Spec .Resources = & v1 .ResourceRequirements {}
140
+ storage .Spec .Resources = & corev1 .ResourceRequirements {}
97
141
}
98
142
99
143
if storage .Spec .Service == nil {
@@ -142,23 +186,35 @@ func (r *Storage) ValidateCreate() error {
142
186
configuration := make (map [string ]interface {})
143
187
err := yaml .Unmarshal ([]byte (r .Spec .Configuration ), & configuration )
144
188
if err != nil {
145
- return fmt .Errorf ("failed to parse Storage.spec.configuration, error: %w" , err )
189
+ return fmt .Errorf ("failed to parse .spec.configuration, error: %w" , err )
190
+ }
191
+
192
+ hostsConfig := PartialHostsConfig {}
193
+ err = yaml .Unmarshal ([]byte (r .Spec .Configuration ), & hostsConfig )
194
+ if err != nil {
195
+ return fmt .Errorf ("failed to parse YAML to determine `hosts`, error: %w" , err )
146
196
}
197
+
147
198
var nodesNumber int32
148
- if configuration [ "hosts" ] == nil {
199
+ if len ( hostsConfig . Hosts ) == 0 {
149
200
nodesNumber = r .Spec .Nodes
150
201
} else {
151
- hosts , ok := configuration ["hosts" ].([]interface {})
152
- if ! ok {
153
- return fmt .Errorf ("failed to parse Storage.spec.configuration, error: invalid hosts section" )
154
- }
155
- nodesNumber = int32 (len (hosts ))
202
+ nodesNumber = int32 (len (hostsConfig .Hosts ))
203
+ }
204
+
205
+ minNodesPerErasure := map [ErasureType ]int32 {
206
+ ErasureMirror3DC : 9 ,
207
+ ErasureBlock42 : 8 ,
208
+ None : 1 ,
209
+ }
210
+ if nodesNumber < minNodesPerErasure [r .Spec .Erasure ] {
211
+ return fmt .Errorf ("erasure type %v requires at least %v storage nodes" , r .Spec .Erasure , minNodesPerErasure [r .Spec .Erasure ])
156
212
}
157
213
158
- yamlConfig := PartialYamlConfig {}
214
+ yamlConfig := PartialDomainsConfig {}
159
215
err = yaml .Unmarshal ([]byte (r .Spec .Configuration ), & yamlConfig )
160
216
if err != nil {
161
- return fmt .Errorf ("failed to parse YAML to determine `enforce_user_token_requirement`" )
217
+ return fmt .Errorf ("failed to parse YAML to determine `enforce_user_token_requirement`, error: %w" , err )
162
218
}
163
219
164
220
var authEnabled bool
@@ -170,15 +226,6 @@ func (r *Storage) ValidateCreate() error {
170
226
return fmt .Errorf ("field 'spec.operatorConnection' does not satisfy with config option `enforce_user_token_requirement: %t`" , authEnabled )
171
227
}
172
228
173
- minNodesPerErasure := map [ErasureType ]int32 {
174
- ErasureMirror3DC : 9 ,
175
- ErasureBlock42 : 8 ,
176
- None : 1 ,
177
- }
178
- if nodesNumber < minNodesPerErasure [r .Spec .Erasure ] {
179
- return fmt .Errorf ("erasure type %v requires at least %v storage nodes" , r .Spec .Erasure , minNodesPerErasure [r .Spec .Erasure ])
180
- }
181
-
182
229
if r .Spec .NodeSets != nil {
183
230
var nodesInSetsCount int32
184
231
for _ , nodeSetInline := range r .Spec .NodeSets {
@@ -237,7 +284,29 @@ func (r *Storage) ValidateUpdate(old runtime.Object) error {
237
284
configuration := make (map [string ]interface {})
238
285
err := yaml .Unmarshal ([]byte (r .Spec .Configuration ), & configuration )
239
286
if err != nil {
240
- return fmt .Errorf ("failed to parse Storage.spec.configuration, error: %w" , err )
287
+ return fmt .Errorf ("failed to parse .spec.configuration, error: %w" , err )
288
+ }
289
+
290
+ hostsConfig := PartialHostsConfig {}
291
+ err = yaml .Unmarshal ([]byte (r .Spec .Configuration ), & hostsConfig )
292
+ if err != nil {
293
+ return fmt .Errorf ("failed to parse YAML to determine `hosts`, error: %w" , err )
294
+ }
295
+
296
+ var nodesNumber int32
297
+ if len (hostsConfig .Hosts ) == 0 {
298
+ nodesNumber = r .Spec .Nodes
299
+ } else {
300
+ nodesNumber = int32 (len (hostsConfig .Hosts ))
301
+ }
302
+
303
+ minNodesPerErasure := map [ErasureType ]int32 {
304
+ ErasureMirror3DC : 9 ,
305
+ ErasureBlock42 : 8 ,
306
+ None : 1 ,
307
+ }
308
+ if nodesNumber < minNodesPerErasure [r .Spec .Erasure ] {
309
+ return fmt .Errorf ("erasure type %v requires at least %v storage nodes" , r .Spec .Erasure , minNodesPerErasure [r .Spec .Erasure ])
241
310
}
242
311
243
312
if ! r .Spec .OperatorSync {
@@ -258,10 +327,10 @@ func (r *Storage) ValidateUpdate(old runtime.Object) error {
258
327
}
259
328
}
260
329
261
- yamlConfig := PartialYamlConfig {}
330
+ yamlConfig := PartialDomainsConfig {}
262
331
err = yaml .Unmarshal ([]byte (r .Spec .Configuration ), & yamlConfig )
263
332
if err != nil {
264
- return fmt .Errorf ("failed to parse YAML to determine `enforce_user_token_requirement`" )
333
+ return fmt .Errorf ("failed to parse YAML to determine `enforce_user_token_requirement`, error: %w" , err )
265
334
}
266
335
267
336
var authEnabled bool
0 commit comments