mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Validation
This commit is contained in:
		@@ -2385,8 +2385,15 @@ var supportedSessionAffinityType = sets.NewString(string(api.ServiceAffinityClie
 | 
				
			|||||||
var supportedServiceType = sets.NewString(string(api.ServiceTypeClusterIP), string(api.ServiceTypeNodePort),
 | 
					var supportedServiceType = sets.NewString(string(api.ServiceTypeClusterIP), string(api.ServiceTypeNodePort),
 | 
				
			||||||
	string(api.ServiceTypeLoadBalancer), string(api.ServiceTypeExternalName))
 | 
						string(api.ServiceTypeLoadBalancer), string(api.ServiceTypeExternalName))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ValidateService tests if required fields in the service are set.
 | 
					// ValidateService tests if required fields/annotations of a Service are valid.
 | 
				
			||||||
func ValidateService(service *api.Service) field.ErrorList {
 | 
					func ValidateService(service *api.Service) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := validateServiceFields(service)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, validateServiceAnnotations(service, nil)...)
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// validateServiceFields tests if required fields in the service are set.
 | 
				
			||||||
 | 
					func validateServiceFields(service *api.Service) field.ErrorList {
 | 
				
			||||||
	allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, field.NewPath("metadata"))
 | 
						allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, field.NewPath("metadata"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	specPath := field.NewPath("spec")
 | 
						specPath := field.NewPath("spec")
 | 
				
			||||||
@@ -2567,6 +2574,63 @@ func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService boo
 | 
				
			|||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func validateServiceAnnotations(service *api.Service, oldService *api.Service) (allErrs field.ErrorList) {
 | 
				
			||||||
 | 
						// 2 annotations went from alpha to beta in 1.5: healthcheck-nodeport and
 | 
				
			||||||
 | 
						// external-traffic. The user cannot mix these. All updates to the alpha
 | 
				
			||||||
 | 
						// annotation are disallowed. The user must change both alpha annotations
 | 
				
			||||||
 | 
						// to beta before making any modifications, even though the system continues
 | 
				
			||||||
 | 
						// to respect the alpha version.
 | 
				
			||||||
 | 
						hcAlpha, healthCheckAlphaOk := service.Annotations[apiservice.AlphaAnnotationHealthCheckNodePort]
 | 
				
			||||||
 | 
						onlyLocalAlpha, onlyLocalAlphaOk := service.Annotations[apiservice.AlphaAnnotationExternalTraffic]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, healthCheckBetaOk := service.Annotations[apiservice.BetaAnnotationHealthCheckNodePort]
 | 
				
			||||||
 | 
						_, onlyLocalBetaOk := service.Annotations[apiservice.BetaAnnotationExternalTraffic]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var oldHealthCheckAlpha, oldOnlyLocalAlpha string
 | 
				
			||||||
 | 
						var oldHealthCheckAlphaOk, oldOnlyLocalAlphaOk bool
 | 
				
			||||||
 | 
						if oldService != nil {
 | 
				
			||||||
 | 
							oldHealthCheckAlpha, oldHealthCheckAlphaOk = oldService.Annotations[apiservice.AlphaAnnotationHealthCheckNodePort]
 | 
				
			||||||
 | 
							oldOnlyLocalAlpha, oldOnlyLocalAlphaOk = oldService.Annotations[apiservice.AlphaAnnotationExternalTraffic]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						hcValueChanged := oldHealthCheckAlphaOk && healthCheckAlphaOk && oldHealthCheckAlpha != hcAlpha
 | 
				
			||||||
 | 
						hcValueNew := !oldHealthCheckAlphaOk && healthCheckAlphaOk
 | 
				
			||||||
 | 
						hcValueGone := !healthCheckAlphaOk && !healthCheckBetaOk && oldHealthCheckAlphaOk
 | 
				
			||||||
 | 
						onlyLocalHCMismatch := onlyLocalBetaOk && healthCheckAlphaOk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// On upgrading to a 1.5 cluster, the user is locked in at the current
 | 
				
			||||||
 | 
						// alpha setting, till they modify the Service such that the pair of
 | 
				
			||||||
 | 
						// annotations are both beta. Basically this means we need to:
 | 
				
			||||||
 | 
						// Disallow updates to the alpha annotation.
 | 
				
			||||||
 | 
						// Disallow creating a Service with the alpha annotation.
 | 
				
			||||||
 | 
						// Disallow removing both alpha annotations. Removing the health-check
 | 
				
			||||||
 | 
						// annotation is rejected at a later stage anyway, so if we allow removing
 | 
				
			||||||
 | 
						// just onlyLocal we might leak the port.
 | 
				
			||||||
 | 
						// Disallow a single field from transitioning to beta. Mismatched annotations
 | 
				
			||||||
 | 
						// cause confusion.
 | 
				
			||||||
 | 
						// Ignore changes to the fields if they're both transitioning to beta.
 | 
				
			||||||
 | 
						// Allow modifications to Services in fields other than the alpha annotation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if hcValueNew || hcValueChanged || hcValueGone || onlyLocalHCMismatch {
 | 
				
			||||||
 | 
							fieldPath := field.NewPath("metadata", "annotations").Key(apiservice.AlphaAnnotationHealthCheckNodePort)
 | 
				
			||||||
 | 
							msg := fmt.Sprintf("please replace the alpha annotation with the beta version %v",
 | 
				
			||||||
 | 
								apiservice.BetaAnnotationHealthCheckNodePort)
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fieldPath, apiservice.AlphaAnnotationHealthCheckNodePort, msg))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onlyLocalValueChanged := oldOnlyLocalAlphaOk && onlyLocalAlphaOk && oldOnlyLocalAlpha != onlyLocalAlpha
 | 
				
			||||||
 | 
						onlyLocalValueNew := !oldOnlyLocalAlphaOk && onlyLocalAlphaOk
 | 
				
			||||||
 | 
						onlyLocalValueGone := !onlyLocalAlphaOk && !onlyLocalBetaOk && oldOnlyLocalAlphaOk
 | 
				
			||||||
 | 
						hcOnlyLocalMismatch := onlyLocalAlphaOk && healthCheckBetaOk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if onlyLocalValueNew || onlyLocalValueChanged || onlyLocalValueGone || hcOnlyLocalMismatch {
 | 
				
			||||||
 | 
							fieldPath := field.NewPath("metadata", "annotations").Key(apiservice.AlphaAnnotationExternalTraffic)
 | 
				
			||||||
 | 
							msg := fmt.Sprintf("please replace the alpha annotation with the beta version %v",
 | 
				
			||||||
 | 
								apiservice.BetaAnnotationExternalTraffic)
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fieldPath, apiservice.AlphaAnnotationExternalTraffic, msg))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ValidateServiceUpdate tests if required fields in the service are set during an update
 | 
					// ValidateServiceUpdate tests if required fields in the service are set during an update
 | 
				
			||||||
func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList {
 | 
					func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList {
 | 
				
			||||||
	allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
 | 
						allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
 | 
				
			||||||
@@ -2578,7 +2642,8 @@ func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList {
 | 
				
			|||||||
	// TODO(freehan): allow user to update loadbalancerSourceRanges
 | 
						// TODO(freehan): allow user to update loadbalancerSourceRanges
 | 
				
			||||||
	allErrs = append(allErrs, ValidateImmutableField(service.Spec.LoadBalancerSourceRanges, oldService.Spec.LoadBalancerSourceRanges, field.NewPath("spec", "loadBalancerSourceRanges"))...)
 | 
						allErrs = append(allErrs, ValidateImmutableField(service.Spec.LoadBalancerSourceRanges, oldService.Spec.LoadBalancerSourceRanges, field.NewPath("spec", "loadBalancerSourceRanges"))...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allErrs = append(allErrs, ValidateService(service)...)
 | 
						allErrs = append(allErrs, validateServiceFields(service)...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, validateServiceAnnotations(service, oldService)...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5207,6 +5207,13 @@ func TestValidateService(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			numErrs: 1,
 | 
								numErrs: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "LoadBalancer disallows onlyLocal alpha annotations",
 | 
				
			||||||
 | 
								tweakSvc: func(s *api.Service) {
 | 
				
			||||||
 | 
									s.Annotations[service.AlphaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficLocal
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								numErrs: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testCases {
 | 
						for _, tc := range testCases {
 | 
				
			||||||
@@ -6474,6 +6481,44 @@ func TestValidateServiceUpdate(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			numErrs: 1,
 | 
								numErrs: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Service disallows removing one onlyLocal alpha annotation",
 | 
				
			||||||
 | 
								tweakSvc: func(oldSvc, newSvc *api.Service) {
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficLocal
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort] = "3001"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								numErrs: 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Service disallows modifying onlyLocal alpha annotations",
 | 
				
			||||||
 | 
								tweakSvc: func(oldSvc, newSvc *api.Service) {
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficLocal
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort] = "3001"
 | 
				
			||||||
 | 
									newSvc.Annotations[service.AlphaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficGlobal
 | 
				
			||||||
 | 
									newSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort] = oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort]
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								numErrs: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Service disallows promoting one of the onlyLocal pair to beta",
 | 
				
			||||||
 | 
								tweakSvc: func(oldSvc, newSvc *api.Service) {
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficLocal
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort] = "3001"
 | 
				
			||||||
 | 
									newSvc.Annotations[service.BetaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficGlobal
 | 
				
			||||||
 | 
									newSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort] = oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort]
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								numErrs: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Service allows changing both onlyLocal annotations from alpha to beta",
 | 
				
			||||||
 | 
								tweakSvc: func(oldSvc, newSvc *api.Service) {
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficLocal
 | 
				
			||||||
 | 
									oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort] = "3001"
 | 
				
			||||||
 | 
									newSvc.Annotations[service.BetaAnnotationExternalTraffic] = service.AnnotationValueExternalTrafficLocal
 | 
				
			||||||
 | 
									newSvc.Annotations[service.BetaAnnotationHealthCheckNodePort] = oldSvc.Annotations[service.AlphaAnnotationHealthCheckNodePort]
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								numErrs: 0,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testCases {
 | 
						for _, tc := range testCases {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -352,14 +352,11 @@ func (rs *REST) healthCheckNodePortUpdate(oldService, service *api.Service) (boo
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case oldServiceHasHealthCheckNodePort && assignHealthCheckNodePort:
 | 
						case oldServiceHasHealthCheckNodePort && assignHealthCheckNodePort:
 | 
				
			||||||
		for _, annotation := range []string{
 | 
							if _, ok := service.Annotations[apiservice.BetaAnnotationHealthCheckNodePort]; !ok {
 | 
				
			||||||
			apiservice.AlphaAnnotationHealthCheckNodePort, apiservice.BetaAnnotationHealthCheckNodePort} {
 | 
								glog.Warningf("Attempt to delete health check node port annotation DENIED")
 | 
				
			||||||
			if _, ok := service.Annotations[annotation]; !ok {
 | 
								el := field.ErrorList{field.Invalid(field.NewPath("metadata", "annotations"),
 | 
				
			||||||
				glog.Warningf("Attempt to delete health check node port annotation DENIED")
 | 
									apiservice.BetaAnnotationHealthCheckNodePort, "Cannot delete healthcheck nodePort annotation")}
 | 
				
			||||||
				el := field.ErrorList{field.Invalid(field.NewPath("metadata", "annotations"),
 | 
								return false, errors.NewInvalid(api.Kind("Service"), service.Name, el)
 | 
				
			||||||
					annotation, "Cannot delete healthcheck nodePort annotation")}
 | 
					 | 
				
			||||||
				return false, errors.NewInvalid(api.Kind("Service"), service.Name, el)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if oldHealthCheckNodePort != requestedHealthCheckNodePort {
 | 
							if oldHealthCheckNodePort != requestedHealthCheckNodePort {
 | 
				
			||||||
			glog.Warningf("Attempt to change value of health check node port annotation DENIED")
 | 
								glog.Warningf("Attempt to change value of health check node port annotation DENIED")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1095,7 +1095,7 @@ var _ = framework.KubeDescribe("ESIPP [Slow][Feature:ExternalTrafficLocalOnly]",
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		c = f.Client
 | 
							c = f.Client
 | 
				
			||||||
		cs = f.ClientSet
 | 
							cs = f.ClientSet
 | 
				
			||||||
		if nodes := framework.GetReadySchedulableNodesOrDie(c); len(nodes.Items) > largeClusterMinNodesNumber {
 | 
							if nodes := framework.GetReadySchedulableNodesOrDie(cs); len(nodes.Items) > largeClusterMinNodesNumber {
 | 
				
			||||||
			loadBalancerCreateTimeout = loadBalancerCreateTimeoutLarge
 | 
								loadBalancerCreateTimeout = loadBalancerCreateTimeoutLarge
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -2104,7 +2104,7 @@ func (j *ServiceTestJig) createOnlyLocalNodePortService(namespace, serviceName s
 | 
				
			|||||||
	svc := j.CreateTCPServiceOrFail(namespace, func(svc *api.Service) {
 | 
						svc := j.CreateTCPServiceOrFail(namespace, func(svc *api.Service) {
 | 
				
			||||||
		svc.Spec.Type = api.ServiceTypeNodePort
 | 
							svc.Spec.Type = api.ServiceTypeNodePort
 | 
				
			||||||
		svc.ObjectMeta.Annotations = map[string]string{
 | 
							svc.ObjectMeta.Annotations = map[string]string{
 | 
				
			||||||
			service.AlphaAnnotationExternalTraffic: service.AnnotationValueExternalTrafficLocal}
 | 
								service.BetaAnnotationExternalTraffic: service.AnnotationValueExternalTrafficLocal}
 | 
				
			||||||
		svc.Spec.Ports = []api.ServicePort{{Protocol: "TCP", Port: 80}}
 | 
							svc.Spec.Ports = []api.ServicePort{{Protocol: "TCP", Port: 80}}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2126,7 +2126,7 @@ func (j *ServiceTestJig) createOnlyLocalLoadBalancerService(namespace, serviceNa
 | 
				
			|||||||
		// We need to turn affinity off for our LB distribution tests
 | 
							// We need to turn affinity off for our LB distribution tests
 | 
				
			||||||
		svc.Spec.SessionAffinity = api.ServiceAffinityNone
 | 
							svc.Spec.SessionAffinity = api.ServiceAffinityNone
 | 
				
			||||||
		svc.ObjectMeta.Annotations = map[string]string{
 | 
							svc.ObjectMeta.Annotations = map[string]string{
 | 
				
			||||||
			service.AlphaAnnotationExternalTraffic: service.AnnotationValueExternalTrafficLocal}
 | 
								service.BetaAnnotationExternalTraffic: service.AnnotationValueExternalTrafficLocal}
 | 
				
			||||||
		svc.Spec.Ports = []api.ServicePort{{Protocol: "TCP", Port: 80}}
 | 
							svc.Spec.Ports = []api.ServicePort{{Protocol: "TCP", Port: 80}}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2171,7 +2171,7 @@ func (j *ServiceTestJig) getEndpointNodes(svc *api.Service) map[string][]string
 | 
				
			|||||||
// getNodes returns the first maxNodesForTest nodes. Useful in large clusters
 | 
					// getNodes returns the first maxNodesForTest nodes. Useful in large clusters
 | 
				
			||||||
// where we don't eg: want to create an endpoint per node.
 | 
					// where we don't eg: want to create an endpoint per node.
 | 
				
			||||||
func (j *ServiceTestJig) getNodes(maxNodesForTest int) (nodes *api.NodeList) {
 | 
					func (j *ServiceTestJig) getNodes(maxNodesForTest int) (nodes *api.NodeList) {
 | 
				
			||||||
	nodes = framework.GetReadySchedulableNodesOrDie(j.Client)
 | 
						nodes = framework.GetReadySchedulableNodesOrDie(j.ClientSet)
 | 
				
			||||||
	if len(nodes.Items) <= maxNodesForTest {
 | 
						if len(nodes.Items) <= maxNodesForTest {
 | 
				
			||||||
		maxNodesForTest = len(nodes.Items)
 | 
							maxNodesForTest = len(nodes.Items)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user