mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Paramaterize stickyMaxAgeMinutes for service in API
This commit is contained in:
		| @@ -15,6 +15,11 @@ | ||||
|       "name": "meteor" | ||||
|     }, | ||||
|     "sessionAffinity": "ClientIP", | ||||
|     "sessionAffinityConfig": { | ||||
|       "clientIP": { | ||||
|         "timeoutSeconds": 90 | ||||
|       } | ||||
|     }, | ||||
|     "type": "LoadBalancer" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2660,6 +2660,31 @@ const ( | ||||
| 	ServiceAffinityNone ServiceAffinity = "None" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// DefaultClientIPServiceAffinitySeconds is the default timeout seconds | ||||
| 	// of Client IP based session affinity - 3 hours. | ||||
| 	DefaultClientIPServiceAffinitySeconds int32 = 10800 | ||||
| 	// MaxClientIPServiceAffinitySeconds is the max timeout seconds | ||||
| 	// of Client IP based session affinity - 1 day. | ||||
| 	MaxClientIPServiceAffinitySeconds int32 = 86400 | ||||
| ) | ||||
|  | ||||
| // SessionAffinityConfig represents the configurations of session affinity. | ||||
| type SessionAffinityConfig struct { | ||||
| 	// clientIP contains the configurations of Client IP based session affinity. | ||||
| 	// +optional | ||||
| 	ClientIP *ClientIPConfig | ||||
| } | ||||
|  | ||||
| // ClientIPConfig represents the configurations of Client IP based session affinity. | ||||
| type ClientIPConfig struct { | ||||
| 	// timeoutSeconds specifies the seconds of ClientIP type session sticky time. | ||||
| 	// The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". | ||||
| 	// Default value is 10800(for 3 hours). | ||||
| 	// +optional | ||||
| 	TimeoutSeconds *int32 | ||||
| } | ||||
|  | ||||
| // Service Type string describes ingress methods for a service | ||||
| type ServiceType string | ||||
|  | ||||
| @@ -2787,6 +2812,10 @@ type ServiceSpec struct { | ||||
| 	// +optional | ||||
| 	SessionAffinity ServiceAffinity | ||||
|  | ||||
| 	// sessionAffinityConfig contains the configurations of session affinity. | ||||
| 	// +optional | ||||
| 	SessionAffinityConfig *SessionAffinityConfig | ||||
|  | ||||
| 	// Optional: If specified and supported by the platform, this will restrict traffic through the cloud-provider | ||||
| 	// load-balancer will be restricted to the specified client IPs. This field will be ignored if the | ||||
| 	// cloud-provider does not support the feature." | ||||
|   | ||||
| @@ -19,6 +19,7 @@ package validation | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"net" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| @@ -28,8 +29,6 @@ import ( | ||||
|  | ||||
| 	"github.com/golang/glog" | ||||
|  | ||||
| 	"math" | ||||
|  | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	apiequality "k8s.io/apimachinery/pkg/api/equality" | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| @@ -1873,6 +1872,33 @@ func validateProbe(probe *api.Probe, fldPath *field.Path) field.ErrorList { | ||||
| 	return allErrs | ||||
| } | ||||
|  | ||||
| func validateClientIPAffinityConfig(config *api.SessionAffinityConfig, fldPath *field.Path) field.ErrorList { | ||||
| 	allErrs := field.ErrorList{} | ||||
| 	if config == nil { | ||||
| 		allErrs = append(allErrs, field.Required(fldPath, fmt.Sprintf("when session affinity type is %s", api.ServiceAffinityClientIP))) | ||||
| 		return allErrs | ||||
| 	} | ||||
| 	if config.ClientIP == nil { | ||||
| 		allErrs = append(allErrs, field.Required(fldPath.Child("clientIP"), fmt.Sprintf("when session affinity type is %s", api.ServiceAffinityClientIP))) | ||||
| 		return allErrs | ||||
| 	} | ||||
| 	if config.ClientIP.TimeoutSeconds == nil { | ||||
| 		allErrs = append(allErrs, field.Required(fldPath.Child("clientIP").Child("timeoutSeconds"), fmt.Sprintf("when session affinity type is %s", api.ServiceAffinityClientIP))) | ||||
| 		return allErrs | ||||
| 	} | ||||
| 	allErrs = append(allErrs, validateAffinityTimeout(config.ClientIP.TimeoutSeconds, fldPath.Child("clientIP").Child("timeoutSeconds"))...) | ||||
|  | ||||
| 	return allErrs | ||||
| } | ||||
|  | ||||
| func validateAffinityTimeout(timeout *int32, fldPath *field.Path) field.ErrorList { | ||||
| 	allErrs := field.ErrorList{} | ||||
| 	if *timeout <= 0 || *timeout > api.MaxClientIPServiceAffinitySeconds { | ||||
| 		allErrs = append(allErrs, field.Invalid(fldPath, timeout, fmt.Sprintf("must be greater than 0 and less than %d", api.MaxClientIPServiceAffinitySeconds))) | ||||
| 	} | ||||
| 	return allErrs | ||||
| } | ||||
|  | ||||
| // AccumulateUniqueHostPorts extracts each HostPort of each Container, | ||||
| // accumulating the results and returning an error if any ports conflict. | ||||
| func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.String, fldPath *field.Path) field.ErrorList { | ||||
| @@ -2914,6 +2940,14 @@ func ValidateService(service *api.Service) field.ErrorList { | ||||
| 		allErrs = append(allErrs, field.NotSupported(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List())) | ||||
| 	} | ||||
|  | ||||
| 	if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { | ||||
| 		allErrs = append(allErrs, validateClientIPAffinityConfig(service.Spec.SessionAffinityConfig, specPath.Child("sessionAffinityConfig"))...) | ||||
| 	} else if service.Spec.SessionAffinity == api.ServiceAffinityNone { | ||||
| 		if service.Spec.SessionAffinityConfig != nil { | ||||
| 			allErrs = append(allErrs, field.Forbidden(specPath.Child("sessionAffinityConfig"), fmt.Sprintf("must not be set when session affinity is %s", string(api.ServiceAffinityNone)))) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if helper.IsServiceIPSet(service) { | ||||
| 		if ip := net.ParseIP(service.Spec.ClusterIP); ip == nil { | ||||
| 			allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty, 'None', or a valid IP address")) | ||||
|   | ||||
| @@ -6792,6 +6792,32 @@ func TestValidateService(t *testing.T) { | ||||
| 			numErrs: 0, | ||||
| 		}, | ||||
| 		// ESIPP section ends. | ||||
| 		{ | ||||
| 			name: "invalid timeoutSeconds field", | ||||
| 			tweakSvc: func(s *api.Service) { | ||||
| 				s.Spec.Type = api.ServiceTypeClusterIP | ||||
| 				s.Spec.SessionAffinity = api.ServiceAffinityClientIP | ||||
| 				s.Spec.SessionAffinityConfig = &api.SessionAffinityConfig{ | ||||
| 					ClientIP: &api.ClientIPConfig{ | ||||
| 						TimeoutSeconds: newInt32(-1), | ||||
| 					}, | ||||
| 				} | ||||
| 			}, | ||||
| 			numErrs: 1, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "sessionAffinityConfig can't be set when session affinity is None", | ||||
| 			tweakSvc: func(s *api.Service) { | ||||
| 				s.Spec.Type = api.ServiceTypeLoadBalancer | ||||
| 				s.Spec.SessionAffinity = api.ServiceAffinityNone | ||||
| 				s.Spec.SessionAffinityConfig = &api.SessionAffinityConfig{ | ||||
| 					ClientIP: &api.ClientIPConfig{ | ||||
| 						TimeoutSeconds: newInt32(90), | ||||
| 					}, | ||||
| 				} | ||||
| 			}, | ||||
| 			numErrs: 1, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| @@ -8193,6 +8219,11 @@ func TestValidateServiceUpdate(t *testing.T) { | ||||
| 			name: "change affinity", | ||||
| 			tweakSvc: func(oldSvc, newSvc *api.Service) { | ||||
| 				newSvc.Spec.SessionAffinity = "ClientIP" | ||||
| 				newSvc.Spec.SessionAffinityConfig = &api.SessionAffinityConfig{ | ||||
| 					ClientIP: &api.ClientIPConfig{ | ||||
| 						TimeoutSeconds: newInt32(90), | ||||
| 					}, | ||||
| 				} | ||||
| 			}, | ||||
| 			numErrs: 0, | ||||
| 		}, | ||||
| @@ -10314,3 +10345,62 @@ func TestValidateFlexVolumeSource(t *testing.T) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestValidateOrSetClientIPAffinityConfig(t *testing.T) { | ||||
| 	successCases := map[string]*api.SessionAffinityConfig{ | ||||
| 		"non-empty config, valid timeout: 1": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: newInt32(1), | ||||
| 			}, | ||||
| 		}, | ||||
| 		"non-empty config, valid timeout: api.MaxClientIPServiceAffinitySeconds-1": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: newInt32(int(api.MaxClientIPServiceAffinitySeconds - 1)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		"non-empty config, valid timeout: api.MaxClientIPServiceAffinitySeconds": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: newInt32(int(api.MaxClientIPServiceAffinitySeconds)), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range successCases { | ||||
| 		if errs := validateClientIPAffinityConfig(test, field.NewPath("field")); len(errs) != 0 { | ||||
| 			t.Errorf("case: %s, expected success: %v", name, errs) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	errorCases := map[string]*api.SessionAffinityConfig{ | ||||
| 		"empty session affinity config": nil, | ||||
| 		"empty client IP config": { | ||||
| 			ClientIP: nil, | ||||
| 		}, | ||||
| 		"empty timeoutSeconds": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: nil, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"non-empty config, invalid timeout: api.MaxClientIPServiceAffinitySeconds+1": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: newInt32(int(api.MaxClientIPServiceAffinitySeconds + 1)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		"non-empty config, invalid timeout: -1": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: newInt32(-1), | ||||
| 			}, | ||||
| 		}, | ||||
| 		"non-empty config, invalid timeout: 0": { | ||||
| 			ClientIP: &api.ClientIPConfig{ | ||||
| 				TimeoutSeconds: newInt32(0), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range errorCases { | ||||
| 		if errs := validateClientIPAffinityConfig(test, field.NewPath("field")); len(errs) == 0 { | ||||
| 			t.Errorf("case: %v, expected failures: %v", name, errs) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -250,6 +250,7 @@ func (c *Controller) CreateOrUpdateMasterServiceIfNeeded(serviceName string, ser | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	timeoutSeconds := api.DefaultClientIPServiceAffinitySeconds | ||||
| 	svc := &api.Service{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      serviceName, | ||||
| @@ -263,6 +264,11 @@ func (c *Controller) CreateOrUpdateMasterServiceIfNeeded(serviceName string, ser | ||||
| 			ClusterIP:       serviceIP.String(), | ||||
| 			SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 			Type:            serviceType, | ||||
| 			SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 				ClientIP: &api.ClientIPConfig{ | ||||
| 					TimeoutSeconds: &timeoutSeconds, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -546,6 +546,7 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 	om := func(name string) metav1.ObjectMeta { | ||||
| 		return metav1.ObjectMeta{Namespace: ns, Name: name} | ||||
| 	} | ||||
| 	timeoutSeconds := api.DefaultClientIPServiceAffinitySeconds | ||||
|  | ||||
| 	create_tests := []struct { | ||||
| 		testName     string | ||||
| @@ -570,6 +571,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -625,6 +631,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -637,6 +648,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -658,6 +674,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -671,6 +692,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -691,6 +717,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -703,6 +734,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -723,6 +759,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -735,6 +776,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -755,6 +801,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -767,6 +818,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -787,6 +843,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -799,6 +860,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -819,6 +885,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeNodePort, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -831,6 +902,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -851,6 +927,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
| @@ -910,6 +991,11 @@ func TestCreateOrUpdateMasterService(t *testing.T) { | ||||
| 					Selector:        nil, | ||||
| 					ClusterIP:       "1.2.3.4", | ||||
| 					SessionAffinity: api.ServiceAffinityClientIP, | ||||
| 					SessionAffinityConfig: &api.SessionAffinityConfig{ | ||||
| 						ClientIP: &api.ClientIPConfig{ | ||||
| 							TimeoutSeconds: &timeoutSeconds, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: api.ServiceTypeClusterIP, | ||||
| 				}, | ||||
| 			}, | ||||
|   | ||||
| @@ -143,7 +143,7 @@ type serviceInfo struct { | ||||
| 	nodePort                 int | ||||
| 	loadBalancerStatus       api.LoadBalancerStatus | ||||
| 	sessionAffinityType      api.ServiceAffinity | ||||
| 	stickyMaxAgeMinutes      int | ||||
| 	stickyMaxAgeSeconds      int | ||||
| 	externalIPs              []string | ||||
| 	loadBalancerSourceRanges []string | ||||
| 	onlyNodeLocalEndpoints   bool | ||||
| @@ -194,6 +194,10 @@ func newServiceInfo(svcPortName proxy.ServicePortName, port *api.ServicePort, se | ||||
| 		apiservice.RequestsOnlyLocalTraffic(service) { | ||||
| 		onlyNodeLocalEndpoints = true | ||||
| 	} | ||||
| 	var stickyMaxAgeSeconds int | ||||
| 	if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { | ||||
| 		stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) | ||||
| 	} | ||||
| 	info := &serviceInfo{ | ||||
| 		clusterIP: net.ParseIP(service.Spec.ClusterIP), | ||||
| 		port:      int(port.Port), | ||||
| @@ -202,11 +206,12 @@ func newServiceInfo(svcPortName proxy.ServicePortName, port *api.ServicePort, se | ||||
| 		// Deep-copy in case the service instance changes | ||||
| 		loadBalancerStatus:       *helper.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer), | ||||
| 		sessionAffinityType:      service.Spec.SessionAffinity, | ||||
| 		stickyMaxAgeMinutes:      180, // TODO: paramaterize this in the API. | ||||
| 		stickyMaxAgeSeconds:      stickyMaxAgeSeconds, | ||||
| 		externalIPs:              make([]string, len(service.Spec.ExternalIPs)), | ||||
| 		loadBalancerSourceRanges: make([]string, len(service.Spec.LoadBalancerSourceRanges)), | ||||
| 		onlyNodeLocalEndpoints:   onlyNodeLocalEndpoints, | ||||
| 	} | ||||
|  | ||||
| 	copy(info.loadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) | ||||
| 	copy(info.externalIPs, service.Spec.ExternalIPs) | ||||
|  | ||||
| @@ -1440,7 +1445,7 @@ func (proxier *Proxier) syncProxyRules() { | ||||
| 					"-A", string(svcChain), | ||||
| 					"-m", "comment", "--comment", svcNameString, | ||||
| 					"-m", "recent", "--name", string(endpointChain), | ||||
| 					"--rcheck", "--seconds", strconv.Itoa(svcInfo.stickyMaxAgeMinutes*60), "--reap", | ||||
| 					"--rcheck", "--seconds", strconv.Itoa(svcInfo.stickyMaxAgeSeconds), "--reap", | ||||
| 					"-j", string(endpointChain)) | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -179,7 +179,7 @@ func TestGetChainLinesMultipleTables(t *testing.T) { | ||||
| func newFakeServiceInfo(service proxy.ServicePortName, ip net.IP, port int, protocol api.Protocol, onlyNodeLocalEndpoints bool) *serviceInfo { | ||||
| 	return &serviceInfo{ | ||||
| 		sessionAffinityType:    api.ServiceAffinityNone,                        // default | ||||
| 		stickyMaxAgeMinutes:    180,                     // TODO: paramaterize this in the API. | ||||
| 		stickyMaxAgeSeconds:    int(api.DefaultClientIPServiceAffinitySeconds), // default | ||||
| 		clusterIP:              ip, | ||||
| 		port:                   port, | ||||
| 		protocol:               protocol, | ||||
|   | ||||
| @@ -28,7 +28,7 @@ type LoadBalancer interface { | ||||
| 	// NextEndpoint returns the endpoint to handle a request for the given | ||||
| 	// service-port and source address. | ||||
| 	NextEndpoint(service proxy.ServicePortName, srcAddr net.Addr, sessionAffinityReset bool) (string, error) | ||||
| 	NewService(service proxy.ServicePortName, sessionAffinityType api.ServiceAffinity, stickyMaxAgeMinutes int) error | ||||
| 	NewService(service proxy.ServicePortName, sessionAffinityType api.ServiceAffinity, stickyMaxAgeSeconds int) error | ||||
| 	DeleteService(service proxy.ServicePortName) | ||||
| 	CleanupStaleStickySessions(service proxy.ServicePortName) | ||||
| 	ServiceHasEndpoints(service proxy.ServicePortName) bool | ||||
|   | ||||
| @@ -61,7 +61,7 @@ type ServiceInfo struct { | ||||
| 	nodePort            int | ||||
| 	loadBalancerStatus  api.LoadBalancerStatus | ||||
| 	sessionAffinityType api.ServiceAffinity | ||||
| 	stickyMaxAgeMinutes int | ||||
| 	stickyMaxAgeSeconds int | ||||
| 	// Deprecated, but required for back-compat (including e2e) | ||||
| 	externalIPs []string | ||||
| } | ||||
| @@ -380,13 +380,11 @@ func (proxier *Proxier) addServiceOnPort(service proxy.ServicePortName, protocol | ||||
| 	si := &ServiceInfo{ | ||||
| 		Timeout:             timeout, | ||||
| 		ActiveClients:       newClientCache(), | ||||
|  | ||||
| 		isAliveAtomic:       1, | ||||
| 		proxyPort:           portNum, | ||||
| 		protocol:            protocol, | ||||
| 		socket:              sock, | ||||
| 		sessionAffinityType: api.ServiceAffinityNone, // default | ||||
| 		stickyMaxAgeMinutes: 180,                     // TODO: parameterize this in the API. | ||||
| 	} | ||||
| 	proxier.setServiceInfo(service, si) | ||||
|  | ||||
| @@ -450,12 +448,17 @@ func (proxier *Proxier) mergeService(service *api.Service) sets.String { | ||||
| 		info.loadBalancerStatus = *helper.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer) | ||||
| 		info.nodePort = int(servicePort.NodePort) | ||||
| 		info.sessionAffinityType = service.Spec.SessionAffinity | ||||
| 		// Set session affinity timeout value when sessionAffinity==ClientIP | ||||
| 		if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { | ||||
| 			info.stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) | ||||
| 		} | ||||
|  | ||||
| 		glog.V(4).Infof("info: %#v", info) | ||||
|  | ||||
| 		if err := proxier.openPortal(serviceName, info); err != nil { | ||||
| 			glog.Errorf("Failed to open portal for %q: %v", serviceName, err) | ||||
| 		} | ||||
| 		proxier.loadBalancer.NewService(serviceName, info.sessionAffinityType, info.stickyMaxAgeMinutes) | ||||
| 		proxier.loadBalancer.NewService(serviceName, info.sessionAffinityType, info.stickyMaxAgeSeconds) | ||||
| 	} | ||||
|  | ||||
| 	return existingPorts | ||||
|   | ||||
| @@ -48,7 +48,7 @@ type affinityState struct { | ||||
| type affinityPolicy struct { | ||||
| 	affinityType api.ServiceAffinity | ||||
| 	affinityMap  map[string]*affinityState // map client IP -> affinity info | ||||
| 	ttlMinutes   int | ||||
| 	ttlSeconds   int | ||||
| } | ||||
|  | ||||
| // LoadBalancerRR is a round-robin load balancer. | ||||
| @@ -66,11 +66,11 @@ type balancerState struct { | ||||
| 	affinity  affinityPolicy | ||||
| } | ||||
|  | ||||
| func newAffinityPolicy(affinityType api.ServiceAffinity, ttlMinutes int) *affinityPolicy { | ||||
| func newAffinityPolicy(affinityType api.ServiceAffinity, ttlSeconds int) *affinityPolicy { | ||||
| 	return &affinityPolicy{ | ||||
| 		affinityType: affinityType, | ||||
| 		affinityMap:  make(map[string]*affinityState), | ||||
| 		ttlMinutes:   ttlMinutes, | ||||
| 		ttlSeconds:   ttlSeconds, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -81,22 +81,22 @@ func NewLoadBalancerRR() *LoadBalancerRR { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (lb *LoadBalancerRR) NewService(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlMinutes int) error { | ||||
| func (lb *LoadBalancerRR) NewService(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlSeconds int) error { | ||||
| 	glog.V(4).Infof("LoadBalancerRR NewService %q", svcPort) | ||||
| 	lb.lock.Lock() | ||||
| 	defer lb.lock.Unlock() | ||||
| 	lb.newServiceInternal(svcPort, affinityType, ttlMinutes) | ||||
| 	lb.newServiceInternal(svcPort, affinityType, ttlSeconds) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // This assumes that lb.lock is already held. | ||||
| func (lb *LoadBalancerRR) newServiceInternal(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlMinutes int) *balancerState { | ||||
| 	if ttlMinutes == 0 { | ||||
| 		ttlMinutes = 180 //default to 3 hours if not specified.  Should 0 be unlimited instead???? | ||||
| func (lb *LoadBalancerRR) newServiceInternal(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlSeconds int) *balancerState { | ||||
| 	if ttlSeconds == 0 { | ||||
| 		ttlSeconds = int(api.DefaultClientIPServiceAffinitySeconds) //default to 3 hours if not specified.  Should 0 be unlimited instead???? | ||||
| 	} | ||||
|  | ||||
| 	if _, exists := lb.services[svcPort]; !exists { | ||||
| 		lb.services[svcPort] = &balancerState{affinity: *newAffinityPolicy(affinityType, ttlMinutes)} | ||||
| 		lb.services[svcPort] = &balancerState{affinity: *newAffinityPolicy(affinityType, ttlSeconds)} | ||||
| 		glog.V(4).Infof("LoadBalancerRR service %q did not exist, created", svcPort) | ||||
| 	} else if affinityType != "" { | ||||
| 		lb.services[svcPort].affinity.affinityType = affinityType | ||||
| @@ -159,7 +159,7 @@ func (lb *LoadBalancerRR) NextEndpoint(svcPort proxy.ServicePortName, srcAddr ne | ||||
| 		} | ||||
| 		if !sessionAffinityReset { | ||||
| 			sessionAffinity, exists := state.affinity.affinityMap[ipaddr] | ||||
| 			if exists && int(time.Now().Sub(sessionAffinity.lastUsed).Minutes()) < state.affinity.ttlMinutes { | ||||
| 			if exists && int(time.Now().Sub(sessionAffinity.lastUsed).Seconds()) < state.affinity.ttlSeconds { | ||||
| 				// Affinity wins. | ||||
| 				endpoint := sessionAffinity.endpoint | ||||
| 				sessionAffinity.lastUsed = time.Now() | ||||
| @@ -378,7 +378,7 @@ func (lb *LoadBalancerRR) CleanupStaleStickySessions(svcPort proxy.ServicePortNa | ||||
| 		return | ||||
| 	} | ||||
| 	for ip, affinity := range state.affinity.affinityMap { | ||||
| 		if int(time.Now().Sub(affinity.lastUsed).Minutes()) >= state.affinity.ttlMinutes { | ||||
| 		if int(time.Now().Sub(affinity.lastUsed).Seconds()) >= state.affinity.ttlSeconds { | ||||
| 			glog.V(4).Infof("Removing client %s from affinityMap for service %q", affinity.clientIP, svcPort) | ||||
| 			delete(state.affinity.affinityMap, ip) | ||||
| 		} | ||||
|   | ||||
| @@ -357,7 +357,7 @@ func TestStickyLoadBalanceWorksWithNewServiceCalledFirst(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	// Call NewService() before OnEndpointsUpdate() | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -421,7 +421,7 @@ func TestStickyLoadBalanceWorksWithNewServiceCalledSecond(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
| 	loadBalancer.OnEndpointsAdd(endpoints) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
|  | ||||
| 	client1 := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} | ||||
| 	client2 := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 2), Port: 0} | ||||
| @@ -473,7 +473,7 @@ func TestStickyLoadBalanaceWorksWithMultipleEndpointsRemoveOne(t *testing.T) { | ||||
| 		t.Errorf("Didn't fail with non-existent service") | ||||
| 	} | ||||
|  | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpointsv1 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -546,7 +546,7 @@ func TestStickyLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) { | ||||
| 		t.Errorf("Didn't fail with non-existent service") | ||||
| 	} | ||||
|  | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpointsv1 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -605,7 +605,7 @@ func TestStickyLoadBalanceWorksWithServiceRemoval(t *testing.T) { | ||||
| 	if err == nil || len(endpoint) != 0 { | ||||
| 		t.Errorf("Didn't fail with non-existent service") | ||||
| 	} | ||||
| 	loadBalancer.NewService(fooService, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(fooService, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints1 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: fooService.Name, Namespace: fooService.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -616,7 +616,7 @@ func TestStickyLoadBalanceWorksWithServiceRemoval(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
| 	barService := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "bar"}, Port: ""} | ||||
| 	loadBalancer.NewService(barService, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(barService, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints2 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: barService.Name, Namespace: barService.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -674,7 +674,7 @@ func TestStickyLoadBalanceWorksWithEndpointFails(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	// Call NewService() before OnEndpointsUpdate() | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
|   | ||||
| @@ -36,7 +36,6 @@ import ( | ||||
| ) | ||||
|  | ||||
| const allAvailableInterfaces string = "" | ||||
| const stickyMaxAgeMinutes int = 180 // TODO: parameterize this in the API. | ||||
|  | ||||
| type portal struct { | ||||
| 	ip         string | ||||
| @@ -360,7 +359,11 @@ func (proxier *Proxier) mergeService(service *api.Service) map[ServicePortPortal | ||||
| 				}, | ||||
| 				Port: servicePort.Name, | ||||
| 			} | ||||
| 			proxier.loadBalancer.NewService(servicePortName, service.Spec.SessionAffinity, stickyMaxAgeMinutes) | ||||
| 			timeoutSeconds := 0 | ||||
| 			if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { | ||||
| 				timeoutSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) | ||||
| 			} | ||||
| 			proxier.loadBalancer.NewService(servicePortName, service.Spec.SessionAffinity, timeoutSeconds) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -48,7 +48,7 @@ type affinityState struct { | ||||
| type affinityPolicy struct { | ||||
| 	affinityType api.ServiceAffinity | ||||
| 	affinityMap  map[string]*affinityState // map client IP -> affinity info | ||||
| 	ttlMinutes   int | ||||
| 	ttlSeconds   int | ||||
| } | ||||
|  | ||||
| // LoadBalancerRR is a round-robin load balancer. | ||||
| @@ -66,11 +66,11 @@ type balancerState struct { | ||||
| 	affinity  affinityPolicy | ||||
| } | ||||
|  | ||||
| func newAffinityPolicy(affinityType api.ServiceAffinity, ttlMinutes int) *affinityPolicy { | ||||
| func newAffinityPolicy(affinityType api.ServiceAffinity, ttlSeconds int) *affinityPolicy { | ||||
| 	return &affinityPolicy{ | ||||
| 		affinityType: affinityType, | ||||
| 		affinityMap:  make(map[string]*affinityState), | ||||
| 		ttlMinutes:   ttlMinutes, | ||||
| 		ttlSeconds:   ttlSeconds, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -81,22 +81,22 @@ func NewLoadBalancerRR() *LoadBalancerRR { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (lb *LoadBalancerRR) NewService(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlMinutes int) error { | ||||
| func (lb *LoadBalancerRR) NewService(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlSeconds int) error { | ||||
| 	glog.V(4).Infof("LoadBalancerRR NewService %q", svcPort) | ||||
| 	lb.lock.Lock() | ||||
| 	defer lb.lock.Unlock() | ||||
| 	lb.newServiceInternal(svcPort, affinityType, ttlMinutes) | ||||
| 	lb.newServiceInternal(svcPort, affinityType, ttlSeconds) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // This assumes that lb.lock is already held. | ||||
| func (lb *LoadBalancerRR) newServiceInternal(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlMinutes int) *balancerState { | ||||
| 	if ttlMinutes == 0 { | ||||
| 		ttlMinutes = 180 //default to 3 hours if not specified.  Should 0 be unlimited instead???? | ||||
| func (lb *LoadBalancerRR) newServiceInternal(svcPort proxy.ServicePortName, affinityType api.ServiceAffinity, ttlSeconds int) *balancerState { | ||||
| 	if ttlSeconds == 0 { | ||||
| 		ttlSeconds = int(api.DefaultClientIPServiceAffinitySeconds) //default to 3 hours if not specified.  Should 0 be unlimited instead???? | ||||
| 	} | ||||
|  | ||||
| 	if _, exists := lb.services[svcPort]; !exists { | ||||
| 		lb.services[svcPort] = &balancerState{affinity: *newAffinityPolicy(affinityType, ttlMinutes)} | ||||
| 		lb.services[svcPort] = &balancerState{affinity: *newAffinityPolicy(affinityType, ttlSeconds)} | ||||
| 		glog.V(4).Infof("LoadBalancerRR service %q did not exist, created", svcPort) | ||||
| 	} else if affinityType != "" { | ||||
| 		lb.services[svcPort].affinity.affinityType = affinityType | ||||
| @@ -149,7 +149,7 @@ func (lb *LoadBalancerRR) NextEndpoint(svcPort proxy.ServicePortName, srcAddr ne | ||||
| 		} | ||||
| 		if !sessionAffinityReset { | ||||
| 			sessionAffinity, exists := state.affinity.affinityMap[ipaddr] | ||||
| 			if exists && int(time.Now().Sub(sessionAffinity.lastUsed).Minutes()) < state.affinity.ttlMinutes { | ||||
| 			if exists && int(time.Now().Sub(sessionAffinity.lastUsed).Seconds()) < state.affinity.ttlSeconds { | ||||
| 				// Affinity wins. | ||||
| 				endpoint := sessionAffinity.endpoint | ||||
| 				sessionAffinity.lastUsed = time.Now() | ||||
| @@ -366,7 +366,7 @@ func (lb *LoadBalancerRR) CleanupStaleStickySessions(svcPort proxy.ServicePortNa | ||||
| 		return | ||||
| 	} | ||||
| 	for ip, affinity := range state.affinity.affinityMap { | ||||
| 		if int(time.Now().Sub(affinity.lastUsed).Minutes()) >= state.affinity.ttlMinutes { | ||||
| 		if int(time.Now().Sub(affinity.lastUsed).Seconds()) >= state.affinity.ttlSeconds { | ||||
| 			glog.V(4).Infof("Removing client %s from affinityMap for service %q", affinity.clientIP, svcPort) | ||||
| 			delete(state.affinity.affinityMap, ip) | ||||
| 		} | ||||
|   | ||||
| @@ -357,7 +357,7 @@ func TestStickyLoadBalanceWorksWithNewServiceCalledFirst(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	// Call NewService() before OnEndpointsUpdate() | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -421,7 +421,7 @@ func TestStickyLoadBalanceWorksWithNewServiceCalledSecond(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
| 	loadBalancer.OnEndpointsAdd(endpoints) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
|  | ||||
| 	client1 := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} | ||||
| 	client2 := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 2), Port: 0} | ||||
| @@ -473,7 +473,7 @@ func TestStickyLoadBalanaceWorksWithMultipleEndpointsRemoveOne(t *testing.T) { | ||||
| 		t.Errorf("Didn't fail with non-existent service") | ||||
| 	} | ||||
|  | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpointsv1 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -546,7 +546,7 @@ func TestStickyLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) { | ||||
| 		t.Errorf("Didn't fail with non-existent service") | ||||
| 	} | ||||
|  | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpointsv1 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -605,7 +605,7 @@ func TestStickyLoadBalanceWorksWithServiceRemoval(t *testing.T) { | ||||
| 	if err == nil || len(endpoint) != 0 { | ||||
| 		t.Errorf("Didn't fail with non-existent service") | ||||
| 	} | ||||
| 	loadBalancer.NewService(fooService, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(fooService, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints1 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: fooService.Name, Namespace: fooService.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -616,7 +616,7 @@ func TestStickyLoadBalanceWorksWithServiceRemoval(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
| 	barService := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "bar"}, Port: ""} | ||||
| 	loadBalancer.NewService(barService, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(barService, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints2 := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: barService.Name, Namespace: barService.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
| @@ -674,7 +674,7 @@ func TestStickyLoadBalanceWorksWithEndpointFails(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	// Call NewService() before OnEndpointsUpdate() | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, 0) | ||||
| 	loadBalancer.NewService(service, api.ServiceAffinityClientIP, int(api.DefaultClientIPServiceAffinitySeconds)) | ||||
| 	endpoints := &api.Endpoints{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, | ||||
| 		Subsets: []api.EndpointSubset{ | ||||
|   | ||||
| @@ -2998,6 +2998,22 @@ const ( | ||||
| 	ServiceAffinityNone ServiceAffinity = "None" | ||||
| ) | ||||
|  | ||||
| // SessionAffinityConfig represents the configurations of session affinity. | ||||
| type SessionAffinityConfig struct { | ||||
| 	// clientIP contains the configurations of Client IP based session affinity. | ||||
| 	// +optional | ||||
| 	ClientIP *ClientIPConfig `json:"clientIP,omitempty" protobuf:"bytes,1,opt,name=clientIP"` | ||||
| } | ||||
|  | ||||
| // ClientIPConfig represents the configurations of Client IP based session affinity. | ||||
| type ClientIPConfig struct { | ||||
| 	// timeoutSeconds specifies the seconds of ClientIP type session sticky time. | ||||
| 	// The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". | ||||
| 	// Default value is 10800(for 3 hours). | ||||
| 	// +optional | ||||
| 	TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty" protobuf:"varint,1,opt,name=timeoutSeconds"` | ||||
| } | ||||
|  | ||||
| // Service Type string describes ingress methods for a service | ||||
| type ServiceType string | ||||
|  | ||||
| @@ -3172,6 +3188,9 @@ type ServiceSpec struct { | ||||
| 	// field. | ||||
| 	// +optional | ||||
| 	PublishNotReadyAddresses bool `json:"publishNotReadyAddresses,omitempty" protobuf:"varint,13,opt,name=publishNotReadyAddresses"` | ||||
| 	// sessionAffinityConfig contains the configurations of session affinity. | ||||
| 	// +optional | ||||
| 	SessionAffinityConfig *SessionAffinityConfig `json:"sessionAffinityConfig,omitempty" protobuf:"bytes,14,opt,name=sessionAffinityConfig"` | ||||
| } | ||||
|  | ||||
| // ServicePort contains information on service's port. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 m1093782566
					m1093782566