@@ -18,6 +18,7 @@ package alibabacloud
18
18
19
19
import (
20
20
"context"
21
+ "fmt"
21
22
gamekruiseiov1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
22
23
"github.com/openkruise/kruise-game/cloudprovider"
23
24
cperrors "github.com/openkruise/kruise-game/cloudprovider/errors"
@@ -30,6 +31,7 @@ import (
30
31
"k8s.io/apimachinery/pkg/types"
31
32
"k8s.io/apimachinery/pkg/util/intstr"
32
33
log "k8s.io/klog/v2"
34
+ "regexp"
33
35
"sigs.k8s.io/controller-runtime/pkg/client"
34
36
"strconv"
35
37
"strings"
@@ -39,6 +41,30 @@ import (
39
41
const (
40
42
NlbNetwork = "AlibabaCloud-NLB"
41
43
AliasNLB = "NLB-Network"
44
+
45
+ // annotations provided by AlibabaCloud Cloud Controller Manager
46
+ LBHealthCheckFlagAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-flag"
47
+ LBHealthCheckTypeAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-type"
48
+ LBHealthCheckConnectPortAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-port"
49
+ LBHealthCheckConnectTimeoutAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-timeout"
50
+ LBHealthyThresholdAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-healthy-threshold"
51
+ LBUnhealthyThresholdAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-unhealthy-threshold"
52
+ LBHealthCheckIntervalAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval"
53
+ LBHealthCheckUriAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-uri"
54
+ LBHealthCheckDomainAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-domain"
55
+ LBHealthCheckMethodAnnotationKey = "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-method"
56
+
57
+ // ConfigNames defined by OKG
58
+ LBHealthCheckFlagConfigName = "LBHealthCheckFlag"
59
+ LBHealthCheckTypeConfigName = "LBHealthCheckType"
60
+ LBHealthCheckConnectPortConfigName = "LBHealthCheckConnectPort"
61
+ LBHealthCheckConnectTimeoutConfigName = "LBHealthCheckConnectTimeout"
62
+ LBHealthCheckIntervalConfigName = "LBHealthCheckInterval"
63
+ LBHealthCheckUriConfigName = "LBHealthCheckUri"
64
+ LBHealthCheckDomainConfigName = "LBHealthCheckDomain"
65
+ LBHealthCheckMethodConfigName = "LBHealthCheckMethod"
66
+ LBHealthyThresholdConfigName = "LBHealthyThreshold"
67
+ LBUnhealthyThresholdConfigName = "LBUnhealthyThreshold"
42
68
)
43
69
44
70
type NlbPlugin struct {
@@ -50,10 +76,20 @@ type NlbPlugin struct {
50
76
}
51
77
52
78
type nlbConfig struct {
53
- lbIds []string
54
- targetPorts []int
55
- protocols []corev1.Protocol
56
- isFixed bool
79
+ lbIds []string
80
+ targetPorts []int
81
+ protocols []corev1.Protocol
82
+ isFixed bool
83
+ lBHealthCheckFlag string
84
+ lBHealthCheckType string
85
+ lBHealthCheckConnectPort string
86
+ lBHealthCheckConnectTimeout string
87
+ lBHealthCheckInterval string
88
+ lBHealthCheckUri string
89
+ lBHealthCheckDomain string
90
+ lBHealthCheckMethod string
91
+ lBHealthyThreshold string
92
+ lBUnhealthyThreshold string
57
93
}
58
94
59
95
func (n * NlbPlugin ) Name () string {
@@ -91,7 +127,10 @@ func (n *NlbPlugin) OnPodUpdated(c client.Client, pod *corev1.Pod, ctx context.C
91
127
92
128
networkStatus , _ := networkManager .GetNetworkStatus ()
93
129
networkConfig := networkManager .GetNetworkConfig ()
94
- sc := parseNlbConfig (networkConfig )
130
+ sc , err := parseNlbConfig (networkConfig )
131
+ if err != nil {
132
+ return pod , cperrors .NewPluginError (cperrors .ParameterError , err .Error ())
133
+ }
95
134
if networkStatus == nil {
96
135
pod , err := networkManager .UpdateNetworkStatus (gamekruiseiov1alpha1.NetworkStatus {
97
136
CurrentNetworkState : gamekruiseiov1alpha1 .NetworkNotReady ,
@@ -101,7 +140,7 @@ func (n *NlbPlugin) OnPodUpdated(c client.Client, pod *corev1.Pod, ctx context.C
101
140
102
141
// get svc
103
142
svc := & corev1.Service {}
104
- err : = c .Get (ctx , types.NamespacedName {
143
+ err = c .Get (ctx , types.NamespacedName {
105
144
Name : pod .GetName (),
106
145
Namespace : pod .GetNamespace (),
107
146
}, svc )
@@ -258,15 +297,31 @@ func (n *NlbPlugin) consSvc(nc *nlbConfig, pod *corev1.Pod, c client.Client, ctx
258
297
259
298
loadBalancerClass := "alibabacloud.com/nlb"
260
299
300
+ svcAnnotations := map [string ]string {
301
+ SlbListenerOverrideKey : "true" ,
302
+ SlbIdAnnotationKey : lbId ,
303
+ SlbConfigHashKey : util .GetHash (nc ),
304
+ LBHealthCheckFlagAnnotationKey : nc .lBHealthCheckFlag ,
305
+ }
306
+ if nc .lBHealthCheckFlag == "on" {
307
+ svcAnnotations [LBHealthCheckTypeAnnotationKey ] = nc .lBHealthCheckType
308
+ svcAnnotations [LBHealthCheckConnectPortAnnotationKey ] = nc .lBHealthCheckConnectPort
309
+ svcAnnotations [LBHealthCheckConnectTimeoutAnnotationKey ] = nc .lBHealthCheckConnectTimeout
310
+ svcAnnotations [LBHealthCheckIntervalAnnotationKey ] = nc .lBHealthCheckInterval
311
+ svcAnnotations [LBHealthyThresholdAnnotationKey ] = nc .lBHealthyThreshold
312
+ svcAnnotations [LBUnhealthyThresholdAnnotationKey ] = nc .lBUnhealthyThreshold
313
+ if nc .lBHealthCheckType == "http" {
314
+ svcAnnotations [LBHealthCheckDomainAnnotationKey ] = nc .lBHealthCheckDomain
315
+ svcAnnotations [LBHealthCheckUriAnnotationKey ] = nc .lBHealthCheckUri
316
+ svcAnnotations [LBHealthCheckMethodAnnotationKey ] = nc .lBHealthCheckMethod
317
+ }
318
+ }
319
+
261
320
svc := & corev1.Service {
262
321
ObjectMeta : metav1.ObjectMeta {
263
- Name : pod .GetName (),
264
- Namespace : pod .GetNamespace (),
265
- Annotations : map [string ]string {
266
- SlbListenerOverrideKey : "true" ,
267
- SlbIdAnnotationKey : lbId ,
268
- SlbConfigHashKey : util .GetHash (nc ),
269
- },
322
+ Name : pod .GetName (),
323
+ Namespace : pod .GetNamespace (),
324
+ Annotations : svcAnnotations ,
270
325
OwnerReferences : getSvcOwnerReference (c , ctx , pod , nc .isFixed ),
271
326
},
272
327
Spec : corev1.ServiceSpec {
@@ -348,11 +403,21 @@ func (n *NlbPlugin) deAllocate(nsName string) {
348
403
log .Infof ("pod %s deallocate nlb %s ports %v" , nsName , lbId , ports )
349
404
}
350
405
351
- func parseNlbConfig (conf []gamekruiseiov1alpha1.NetworkConfParams ) * nlbConfig {
406
+ func parseNlbConfig (conf []gamekruiseiov1alpha1.NetworkConfParams ) ( * nlbConfig , error ) {
352
407
var lbIds []string
353
408
ports := make ([]int , 0 )
354
409
protocols := make ([]corev1.Protocol , 0 )
355
410
isFixed := false
411
+ lBHealthCheckFlag := "on"
412
+ lBHealthCheckType := "tcp"
413
+ lBHealthCheckConnectPort := "0"
414
+ lBHealthCheckConnectTimeout := "5"
415
+ lBHealthCheckInterval := "10"
416
+ lBUnhealthyThreshold := "2"
417
+ lBHealthyThreshold := "2"
418
+ lBHealthCheckUri := ""
419
+ lBHealthCheckDomain := ""
420
+ lBHealthCheckMethod := ""
356
421
for _ , c := range conf {
357
422
switch c .Name {
358
423
case NlbIdsConfigName :
@@ -381,12 +446,138 @@ func parseNlbConfig(conf []gamekruiseiov1alpha1.NetworkConfParams) *nlbConfig {
381
446
continue
382
447
}
383
448
isFixed = v
449
+ case LBHealthCheckFlagConfigName :
450
+ flag := strings .ToLower (c .Value )
451
+ if flag != "on" && flag != "off" {
452
+ return nil , fmt .Errorf ("invalid lb health check flag value: %s" , c .Value )
453
+ }
454
+ lBHealthCheckFlag = flag
455
+ case LBHealthCheckTypeConfigName :
456
+ checkType := strings .ToLower (c .Value )
457
+ if checkType != "tcp" && checkType != "http" {
458
+ return nil , fmt .Errorf ("invalid lb health check type: %s" , c .Value )
459
+ }
460
+ lBHealthCheckType = checkType
461
+ case LBHealthCheckConnectPortConfigName :
462
+ portInt , err := strconv .Atoi (c .Value )
463
+ if err != nil {
464
+ return nil , fmt .Errorf ("invalid lb health check connect port: %s" , c .Value )
465
+ }
466
+ if portInt < 0 || portInt > 65535 {
467
+ return nil , fmt .Errorf ("invalid lb health check connect port: %d" , portInt )
468
+ }
469
+ lBHealthCheckConnectPort = c .Value
470
+ case LBHealthCheckConnectTimeoutConfigName :
471
+ timeoutInt , err := strconv .Atoi (c .Value )
472
+ if err != nil {
473
+ return nil , fmt .Errorf ("invalid lb health check connect timeout: %s" , c .Value )
474
+ }
475
+ if timeoutInt < 1 || timeoutInt > 300 {
476
+ return nil , fmt .Errorf ("invalid lb health check connect timeout: %d" , timeoutInt )
477
+ }
478
+ lBHealthCheckConnectTimeout = c .Value
479
+ case LBHealthCheckIntervalConfigName :
480
+ intervalInt , err := strconv .Atoi (c .Value )
481
+ if err != nil {
482
+ return nil , fmt .Errorf ("invalid lb health check interval: %s" , c .Value )
483
+ }
484
+ if intervalInt < 1 || intervalInt > 50 {
485
+ return nil , fmt .Errorf ("invalid lb health check interval: %d" , intervalInt )
486
+ }
487
+ lBHealthCheckInterval = c .Value
488
+ case LBHealthyThresholdConfigName :
489
+ thresholdInt , err := strconv .Atoi (c .Value )
490
+ if err != nil {
491
+ return nil , fmt .Errorf ("invalid lb healthy threshold: %s" , c .Value )
492
+ }
493
+ if thresholdInt < 2 || thresholdInt > 10 {
494
+ return nil , fmt .Errorf ("invalid lb healthy threshold: %d" , thresholdInt )
495
+ }
496
+ lBHealthyThreshold = c .Value
497
+ case LBUnhealthyThresholdConfigName :
498
+ thresholdInt , err := strconv .Atoi (c .Value )
499
+ if err != nil {
500
+ return nil , fmt .Errorf ("invalid lb unhealthy threshold: %s" , c .Value )
501
+ }
502
+ if thresholdInt < 2 || thresholdInt > 10 {
503
+ return nil , fmt .Errorf ("invalid lb unhealthy threshold: %d" , thresholdInt )
504
+ }
505
+ lBUnhealthyThreshold = c .Value
506
+ case LBHealthCheckUriConfigName :
507
+ if validateUri (c .Value ) != nil {
508
+ return nil , fmt .Errorf ("invalid lb health check uri: %s" , c .Value )
509
+ }
510
+ lBHealthCheckUri = c .Value
511
+ case LBHealthCheckDomainConfigName :
512
+ if validateDomain (c .Value ) != nil {
513
+ return nil , fmt .Errorf ("invalid lb health check domain: %s" , c .Value )
514
+ }
515
+ lBHealthCheckDomain = c .Value
516
+ case LBHealthCheckMethodConfigName :
517
+ method := strings .ToLower (c .Value )
518
+ if method != "get" && method != "head" {
519
+ return nil , fmt .Errorf ("invalid lb health check method: %s" , c .Value )
520
+ }
521
+ lBHealthCheckMethod = method
384
522
}
385
523
}
386
524
return & nlbConfig {
387
- lbIds : lbIds ,
388
- protocols : protocols ,
389
- targetPorts : ports ,
390
- isFixed : isFixed ,
525
+ lbIds : lbIds ,
526
+ protocols : protocols ,
527
+ targetPorts : ports ,
528
+ isFixed : isFixed ,
529
+ lBHealthCheckFlag : lBHealthCheckFlag ,
530
+ lBHealthCheckType : lBHealthCheckType ,
531
+ lBHealthCheckConnectPort : lBHealthCheckConnectPort ,
532
+ lBHealthCheckConnectTimeout : lBHealthCheckConnectTimeout ,
533
+ lBHealthCheckInterval : lBHealthCheckInterval ,
534
+ lBHealthCheckUri : lBHealthCheckUri ,
535
+ lBHealthCheckDomain : lBHealthCheckDomain ,
536
+ lBHealthCheckMethod : lBHealthCheckMethod ,
537
+ lBHealthyThreshold : lBHealthyThreshold ,
538
+ lBUnhealthyThreshold : lBUnhealthyThreshold ,
539
+ }, nil
540
+ }
541
+
542
+ func validateDomain (domain string ) error {
543
+ if len (domain ) < 1 || len (domain ) > 80 {
544
+ return fmt .Errorf ("the domain length must be between 1 and 80 characters" )
545
+ }
546
+
547
+ // Regular expression matches lowercase letters, numbers, dashes and periods
548
+ domainRegex := regexp .MustCompile (`^[a-z0-9-.]+$` )
549
+ if ! domainRegex .MatchString (domain ) {
550
+ return fmt .Errorf ("the domain must only contain lowercase letters, numbers, hyphens, and periods" )
551
+ }
552
+
553
+ // make sure the domain name does not start or end with a dash or period
554
+ if domain [0 ] == '-' || domain [0 ] == '.' || domain [len (domain )- 1 ] == '-' || domain [len (domain )- 1 ] == '.' {
555
+ return fmt .Errorf ("the domain must not start or end with a hyphen or period" )
556
+ }
557
+
558
+ // make sure the domain name does not contain consecutive dots or dashes
559
+ if regexp .MustCompile (`(--|\.\.)` ).MatchString (domain ) {
560
+ return fmt .Errorf ("the domain must not contain consecutive hyphens or periods" )
561
+ }
562
+
563
+ return nil
564
+ }
565
+
566
+ func validateUri (uri string ) error {
567
+ if len (uri ) < 1 || len (uri ) > 80 {
568
+ return fmt .Errorf ("string length must be between 1 and 80 characters" )
569
+ }
570
+
571
+ regexPattern := `^/[0-9a-zA-Z.!$%&'*+/=?^_` + "`" + `{|}~-]*$`
572
+ matched , err := regexp .MatchString (regexPattern , uri )
573
+
574
+ if err != nil {
575
+ return fmt .Errorf ("regex error: %v" , err )
576
+ }
577
+
578
+ if ! matched {
579
+ return fmt .Errorf ("string does not match the required pattern" )
391
580
}
581
+
582
+ return nil
392
583
}
0 commit comments