Skip to content

Commit

Permalink
Merge pull request #1130 from MartinForReal/release-1.0_backport_pr963
Browse files Browse the repository at this point in the history
[release-1.0]Fix: health probe config should be port-specific
  • Loading branch information
k8s-ci-robot committed Feb 15, 2022
2 parents e9bcaa8 + 0415e78 commit 292d67c
Show file tree
Hide file tree
Showing 8 changed files with 1,100 additions and 247 deletions.
44 changes: 44 additions & 0 deletions pkg/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ const (
// If not set, the local service would use the HTTP and the cluster service would use the TCP by default.
ServiceAnnotationLoadBalancerHealthProbeProtocol = "service.beta.kubernetes.io/azure-load-balancer-health-probe-protocol"

// ServiceAnnotationLoadBalancerHealthProbeInterval determines the probe interval of the load balancer health probe.
// The minimum probe interval is 5 seconds and the default value is 15. The total duration of all intervals cannot exceed 120 seconds.
ServiceAnnotationLoadBalancerHealthProbeInterval = "service.beta.kubernetes.io/azure-load-balancer-health-probe-interval"

// ServiceAnnotationLoadBalancerHealthProbeNumOfProbe determines the minimum number of unhealthy responses which load balancer cannot tolerate.
// The minimum number of probe is 1. The total duration of all intervals cannot exceed 120 seconds.
ServiceAnnotationLoadBalancerHealthProbeNumOfProbe = "service.beta.kubernetes.io/azure-load-balancer-health-probe-num-of-probe"

// ServiceAnnotationLoadBalancerHealthProbeRequestPath determines the request path of the load balancer health probe.
// This is only useful for the HTTP and HTTPS, and would be ignored when using TCP. If not set,
// `/healthz` would be configured by default.
Expand Down Expand Up @@ -346,3 +354,39 @@ const (
RouteNameFmt = "%s____%s"
RouteNameSeparator = "____"
)

// cloud provider config secret
const (
DefaultCloudProviderConfigSecName = "azure-cloud-provider"
DefaultCloudProviderConfigSecNamespace = "kube-system"
DefaultCloudProviderConfigSecKey = "cloud-config"
)

// RateLimited error string
const RateLimited = "rate limited"

// CreatedByTag tag key for CSI drivers
const CreatedByTag = "k8s-azure-created-by"

// health probe
const (
HealthProbeAnnotationPrefixPattern = "service.beta.kubernetes.io/port_%d_health-probe_"

// HealthProbeParamsProbeInterval determines the probe interval of the load balancer health probe.
// The minimum probe interval is 5 seconds and the default value is 5. The total duration of all intervals cannot exceed 120 seconds.
HealthProbeParamsProbeInterval HealthProbeParams = "interval"
HealthProbeDefaultProbeInterval int32 = 5

// HealthProbeParamsNumOfProbe determines the minimum number of unhealthy responses which load balancer cannot tolerate.
// The minimum number of probe is 2. The total duration of all intervals cannot exceed 120 seconds.
HealthProbeParamsNumOfProbe HealthProbeParams = "num-of-probe"
HealthProbeDefaultNumOfProbe int32 = 2

// HealthProbeParamsRequestPath determines the request path of the load balancer health probe.
// This is only useful for the HTTP and HTTPS, and would be ignored when using TCP. If not set,
// `/healthz` would be configured by default.
HealthProbeParamsRequestPath HealthProbeParams = "request-path"
HealthProbeDefaultRequestPath string = "/healthz"
)

type HealthProbeParams string
109 changes: 109 additions & 0 deletions pkg/consts/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package consts stages all the consts under pkg/.
package consts

import (
"fmt"
"strconv"
"strings"

v1 "k8s.io/api/core/v1"
)

// IsK8sServiceHasHAModeEnabled return if HA Mode is enabled in kuberntes service annotations
func IsK8sServiceHasHAModeEnabled(service *v1.Service) bool {
return expectAttributeInSvcAnnotationBeEqualTo(service.Annotations, ServiceAnnotationLoadBalancerEnableHighAvailabilityPorts, TrueAnnotationValue)
}

// IsK8sServiceUsingInternalLoadBalancer return if service is using an internal load balancer.
func IsK8sServiceUsingInternalLoadBalancer(service *v1.Service) bool {
return expectAttributeInSvcAnnotationBeEqualTo(service.Annotations, ServiceAnnotationLoadBalancerInternal, TrueAnnotationValue)
}

// GetHealthProbeConfigOfPortFromK8sSvcAnnotation get health probe configuration for port
func GetHealthProbeConfigOfPortFromK8sSvcAnnotation(annotations map[string]string, port int32, key HealthProbeParams, validators ...BusinessValidator) (*string, error) {
return GetAttributeValueInSvcAnnotation(annotations, BuildHealthProbeAnnotationKeyForPort(port, key), validators...)
}

// Getint32ValueFromK8sSvcAnnotation get health probe configuration for port
func Getint32ValueFromK8sSvcAnnotation(annotations map[string]string, key string, validators ...Int32BusinessValidator) (*int32, error) {
val, err := GetAttributeValueInSvcAnnotation(annotations, key)
if err == nil && val != nil {
return extractInt32FromString(*val, validators...)
}
return nil, err
}

// BuildHealthProbeAnnotationKeyForPort get health probe configuration key for port
func BuildHealthProbeAnnotationKeyForPort(port int32, key HealthProbeParams) string {
return fmt.Sprintf(HealthProbeAnnotationPrefixPattern, port) + string(key)
}

// GetInt32HealthProbeConfigOfPortFromK8sSvcAnnotation get health probe configuration for port
func GetInt32HealthProbeConfigOfPortFromK8sSvcAnnotation(annotations map[string]string, port int32, key HealthProbeParams, validators ...Int32BusinessValidator) (*int32, error) {
return Getint32ValueFromK8sSvcAnnotation(annotations, BuildHealthProbeAnnotationKeyForPort(port, key), validators...)
}

// Int32BusinessValidator is validator function which is invoked after values are parsed in order to make sure input value meets the businees need.
type Int32BusinessValidator func(*int32) error

// getInt32FromAnnotations parse integer value from annotation and return an reference to int32 object
func extractInt32FromString(val string, businessValidator ...Int32BusinessValidator) (*int32, error) {
val = strings.TrimSpace(val)
errKey := fmt.Errorf("%s value must be a whole number", val)
toInt, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return nil, fmt.Errorf("error value: %w: %v", err, errKey)
}
parsedInt := int32(toInt)
for _, validator := range businessValidator {
if validator != nil {
err := validator(&parsedInt)
if err != nil {
return nil, fmt.Errorf("error parsing value: %w", err)
}
}
}
return &parsedInt, nil
}

// BusinessValidator is validator function which is invoked after values are parsed in order to make sure input value meets the businees need.
type BusinessValidator func(*string) error

// GetAttributeValueInSvcAnnotation get value in annotation map using key
func GetAttributeValueInSvcAnnotation(annotations map[string]string, key string, validators ...BusinessValidator) (*string, error) {
if l, found := annotations[key]; found {
for _, validateFunc := range validators {
if validateFunc != nil {
if err := validateFunc(&l); err != nil {
return nil, err
}
}
}
return &l, nil
}
return nil, nil
}

// expectAttributeInSvcAnnotation get key in svc annotation and compare with target value
func expectAttributeInSvcAnnotationBeEqualTo(annotations map[string]string, key string, value string) bool {
if l, err := GetAttributeValueInSvcAnnotation(annotations, key); err == nil && l != nil {
return strings.EqualFold(*l, value)
}
return false
}

0 comments on commit 292d67c

Please sign in to comment.