Mark ServiceLBNodePortControl as GA

This commit is contained in:
Lars Ekman 2021-12-16 16:48:58 +01:00
parent bafe301630
commit 1ef96752da
12 changed files with 31 additions and 137 deletions

View File

@ -3892,7 +3892,6 @@ type ServiceSpec struct {
// value), those requests will be respected, regardless of this field.
// This field may only be set for services with type LoadBalancer and will
// be cleared if the type is changed to any other type.
// This field is beta-level and is only honored by servers that enable the ServiceLBNodePortControl feature.
// +optional
AllocateLoadBalancerNodePorts *bool

View File

@ -136,11 +136,9 @@ func SetDefaults_Service(obj *v1.Service) {
obj.Spec.InternalTrafficPolicy = &serviceInternalTrafficPolicyCluster
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
if obj.Spec.Type == v1.ServiceTypeLoadBalancer {
if obj.Spec.AllocateLoadBalancerNodePorts == nil {
obj.Spec.AllocateLoadBalancerNodePorts = utilpointer.BoolPtr(true)
}
if obj.Spec.Type == v1.ServiceTypeLoadBalancer {
if obj.Spec.AllocateLoadBalancerNodePorts == nil {
obj.Spec.AllocateLoadBalancerNodePorts = utilpointer.BoolPtr(true)
}
}
}

View File

@ -4685,10 +4685,8 @@ func ValidateService(service *core.Service) field.ErrorList {
allErrs = append(allErrs, field.Forbidden(specPath.Child("allocateLoadBalancerNodePorts"), "may only be used when `type` is 'LoadBalancer'"))
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
if service.Spec.Type == core.ServiceTypeLoadBalancer && service.Spec.AllocateLoadBalancerNodePorts == nil {
allErrs = append(allErrs, field.Required(field.NewPath("allocateLoadBalancerNodePorts"), ""))
}
if service.Spec.Type == core.ServiceTypeLoadBalancer && service.Spec.AllocateLoadBalancerNodePorts == nil {
allErrs = append(allErrs, field.Required(field.NewPath("allocateLoadBalancerNodePorts"), ""))
}
// validate LoadBalancerClass field

View File

@ -932,7 +932,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
KubeletCredentialProviders: {Default: false, PreRelease: featuregate.Alpha},
GracefulNodeShutdown: {Default: true, PreRelease: featuregate.Beta},
GracefulNodeShutdownBasedOnPodPriority: {Default: false, PreRelease: featuregate.Alpha},
ServiceLBNodePortControl: {Default: true, PreRelease: featuregate.Beta},
ServiceLBNodePortControl: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha},
VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha},
PreferNominatedNode: {Default: true, PreRelease: featuregate.Beta},

View File

@ -26,10 +26,8 @@ import (
"k8s.io/apiserver/pkg/admission"
quota "k8s.io/apiserver/pkg/quota/v1"
"k8s.io/apiserver/pkg/quota/v1/generic"
"k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/features"
)
// the name used for object count quota
@ -134,8 +132,7 @@ func (p *serviceEvaluator) Usage(item runtime.Object) (corev1.ResourceList, erro
// is suppressed only ports with explicit NodePort values are counted.
// nodeports won't be allocated yet, so we can't simply count the actual values.
// We need to look at the intent.
if feature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) &&
svc.Spec.AllocateLoadBalancerNodePorts != nil &&
if svc.Spec.AllocateLoadBalancerNodePorts != nil &&
*svc.Spec.AllocateLoadBalancerNodePorts == false {
result[corev1.ResourceServicesNodePorts] = *portsWithNodePorts(svc)
} else {

View File

@ -24,10 +24,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
quota "k8s.io/apiserver/pkg/quota/v1"
"k8s.io/apiserver/pkg/quota/v1/generic"
"k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
utilpointer "k8s.io/utils/pointer"
)
@ -56,9 +53,8 @@ func TestServiceEvaluatorMatchesResources(t *testing.T) {
func TestServiceEvaluatorUsage(t *testing.T) {
evaluator := NewServiceEvaluator(nil)
testCases := map[string]struct {
service *api.Service
usage corev1.ResourceList
serviceLBNodePortControlEnabled bool
service *api.Service
usage corev1.ResourceList
}{
"loadbalancer": {
service: &api.Service{
@ -185,7 +181,6 @@ func TestServiceEvaluatorUsage(t *testing.T) {
corev1.ResourceServicesLoadBalancers: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
serviceLBNodePortControlEnabled: true,
},
"nodeports-default-enabled": {
service: &api.Service{
@ -232,7 +227,6 @@ func TestServiceEvaluatorUsage(t *testing.T) {
corev1.ResourceServicesLoadBalancers: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
serviceLBNodePortControlEnabled: true,
},
"nodeports-disabled-but-specified": {
service: &api.Service{
@ -257,12 +251,10 @@ func TestServiceEvaluatorUsage(t *testing.T) {
corev1.ResourceServicesLoadBalancers: resource.MustParse("1"),
generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "services"}): resource.MustParse("1"),
},
serviceLBNodePortControlEnabled: true,
},
}
for testName, testCase := range testCases {
t.Run(testName, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceLBNodePortControl, testCase.serviceLBNodePortControlEnabled)()
actual, err := evaluator.Usage(testCase.service)
if err != nil {
t.Errorf("%s unexpected error: %v", testName, err)

View File

@ -22,12 +22,10 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
apiservice "k8s.io/kubernetes/pkg/api/service"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
netutils "k8s.io/utils/net"
@ -940,10 +938,7 @@ func shouldAllocateNodePorts(service *api.Service) bool {
return true
}
if service.Spec.Type == api.ServiceTypeLoadBalancer {
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
return *service.Spec.AllocateLoadBalancerNodePorts
}
return true
return *service.Spec.AllocateLoadBalancerNodePorts
}
return false
}

View File

@ -6103,12 +6103,11 @@ func TestCreateDeleteReuse(t *testing.T) {
func TestCreateInitNodePorts(t *testing.T) {
testCases := []struct {
name string
svc *api.Service
expectError bool
expectNodePorts bool
gateMixedProtocolLBService bool
gateServiceLBNodePortControl bool
name string
svc *api.Service
expectError bool
expectNodePorts bool
gateMixedProtocolLBService bool
}{{
name: "type:ExternalName",
svc: svctest.MakeService("foo"),
@ -6199,108 +6198,51 @@ func TestCreateInitNodePorts(t *testing.T) {
svctest.SetNodePorts(30093, 30093)),
expectError: true,
}, {
// When the ServiceLBNodePortControl gate is locked, this can be removed.
name: "type:LoadBalancer_single_port_unspecified_gateServiceLBNodePortControl:off_alloc:nil",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer),
gateServiceLBNodePortControl: false,
expectNodePorts: true,
}, {
// When the ServiceLBNodePortControl gate is locked, this can be removed.
name: "type:LoadBalancer_single_port_unspecified_gateServiceLBNodePortControl:off_alloc:false",
name: "type:LoadBalancer_single_port_unspecified:on_alloc:false",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetAllocateLoadBalancerNodePorts(false)),
gateServiceLBNodePortControl: false,
expectNodePorts: true,
expectNodePorts: false,
}, {
// When the ServiceLBNodePortControl gate is locked, this can be removed.
name: "type:LoadBalancer_single_port_unspecified_gateServiceLBNodePortControl:off_alloc:true",
name: "type:LoadBalancer_single_port_unspecified:on_alloc:true",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetAllocateLoadBalancerNodePorts(true)),
gateServiceLBNodePortControl: false,
expectNodePorts: true,
expectNodePorts: true,
}, {
// When the ServiceLBNodePortControl gate is locked, this can be removed.
name: "type:LoadBalancer_single_port_specified_gateServiceLBNodePortControl:off",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer, svctest.SetUniqueNodePorts),
gateServiceLBNodePortControl: false,
expectNodePorts: true,
}, {
// When the ServiceLBNodePortControl gate is locked, this can be removed.
name: "type:LoadBalancer_multiport_unspecified_gateServiceLBNodePortControl:off",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetPorts(
svctest.MakeServicePort("p", 80, intstr.FromInt(80), api.ProtocolTCP),
svctest.MakeServicePort("q", 443, intstr.FromInt(443), api.ProtocolTCP))),
gateServiceLBNodePortControl: false,
expectNodePorts: true,
}, {
// When the ServiceLBNodePortControl gate is locked, this can be removed.
name: "type:LoadBalancer_multiport_specified_gateServiceLBNodePortControl:off",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetPorts(
svctest.MakeServicePort("p", 80, intstr.FromInt(80), api.ProtocolTCP),
svctest.MakeServicePort("q", 443, intstr.FromInt(443), api.ProtocolTCP)),
svctest.SetUniqueNodePorts),
gateServiceLBNodePortControl: false,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_single_port_unspecified_gateServiceLBNodePortControl:on_alloc:false",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetAllocateLoadBalancerNodePorts(false)),
gateServiceLBNodePortControl: true,
expectNodePorts: false,
}, {
name: "type:LoadBalancer_single_port_unspecified_gateServiceLBNodePortControl:on_alloc:true",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetAllocateLoadBalancerNodePorts(true)),
gateServiceLBNodePortControl: true,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_single_port_specified_gateServiceLBNodePortControl:on_alloc:false",
name: "type:LoadBalancer_single_port_specified:on_alloc:false",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetUniqueNodePorts,
svctest.SetAllocateLoadBalancerNodePorts(false)),
gateServiceLBNodePortControl: true,
expectNodePorts: true,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_single_port_specified_gateServiceLBNodePortControl:on_alloc:true",
name: "type:LoadBalancer_single_port_specified:on_alloc:true",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetUniqueNodePorts,
svctest.SetAllocateLoadBalancerNodePorts(true)),
gateServiceLBNodePortControl: true,
expectNodePorts: true,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_multiport_unspecified_gateServiceLBNodePortControl:on_alloc:false",
name: "type:LoadBalancer_multiport_unspecified:on_alloc:false",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetPorts(
svctest.MakeServicePort("p", 80, intstr.FromInt(80), api.ProtocolTCP),
svctest.MakeServicePort("q", 443, intstr.FromInt(443), api.ProtocolTCP)),
svctest.SetAllocateLoadBalancerNodePorts(false)),
gateServiceLBNodePortControl: true,
expectNodePorts: false,
expectNodePorts: false,
}, {
name: "type:LoadBalancer_multiport_unspecified_gateServiceLBNodePortControl:on_alloc:true",
name: "type:LoadBalancer_multiport_unspecified:on_alloc:true",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetPorts(
svctest.MakeServicePort("p", 80, intstr.FromInt(80), api.ProtocolTCP),
svctest.MakeServicePort("q", 443, intstr.FromInt(443), api.ProtocolTCP)),
svctest.SetAllocateLoadBalancerNodePorts(true)),
gateServiceLBNodePortControl: true,
expectNodePorts: true,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_multiport_specified_gateServiceLBNodePortControl:on_alloc:false",
name: "type:LoadBalancer_multiport_specified:on_alloc:false",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetPorts(
@ -6308,10 +6250,9 @@ func TestCreateInitNodePorts(t *testing.T) {
svctest.MakeServicePort("q", 443, intstr.FromInt(443), api.ProtocolTCP)),
svctest.SetUniqueNodePorts,
svctest.SetAllocateLoadBalancerNodePorts(false)),
gateServiceLBNodePortControl: true,
expectNodePorts: true,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_multiport_specified_gateServiceLBNodePortControl:on_alloc:true",
name: "type:LoadBalancer_multiport_specified:on_alloc:true",
svc: svctest.MakeService("foo",
svctest.SetTypeLoadBalancer,
svctest.SetPorts(
@ -6319,8 +6260,7 @@ func TestCreateInitNodePorts(t *testing.T) {
svctest.MakeServicePort("q", 443, intstr.FromInt(443), api.ProtocolTCP)),
svctest.SetUniqueNodePorts,
svctest.SetAllocateLoadBalancerNodePorts(true)),
gateServiceLBNodePortControl: true,
expectNodePorts: true,
expectNodePorts: true,
}, {
name: "type:LoadBalancer_multiport_same",
svc: svctest.MakeService("foo",
@ -6408,7 +6348,6 @@ func TestCreateInitNodePorts(t *testing.T) {
defer storage.Store.DestroyFunc()
for _, tc := range testCases {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, tc.gateServiceLBNodePortControl)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MixedProtocolLBService, tc.gateMixedProtocolLBService)()
t.Run(tc.name, func(t *testing.T) {

View File

@ -162,12 +162,6 @@ func (svcStrategy) AllowUnconditionalUpdate() bool {
// newSvc.Spec.MyFeature = nil
// }
func dropServiceDisabledFields(newSvc *api.Service, oldSvc *api.Service) {
// Clear AllocateLoadBalancerNodePorts if ServiceLBNodePortControl is not enabled
if !utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
if !allocateLoadBalancerNodePortsInUse(oldSvc) {
newSvc.Spec.AllocateLoadBalancerNodePorts = nil
}
}
if !utilfeature.DefaultFeatureGate.Enabled(features.MixedProtocolLBService) {
if !serviceConditionsInUse(oldSvc) {
@ -195,14 +189,6 @@ func dropServiceDisabledFields(newSvc *api.Service, oldSvc *api.Service) {
}
}
// returns true if svc.Spec.AllocateLoadBalancerNodePorts field is in use
func allocateLoadBalancerNodePortsInUse(svc *api.Service) bool {
if svc == nil {
return false
}
return svc.Spec.AllocateLoadBalancerNodePorts != nil
}
// returns true when the svc.Status.Conditions field is in use.
func serviceConditionsInUse(svc *api.Service) bool {
if svc == nil {

View File

@ -4460,8 +4460,6 @@ type ServiceSpec struct {
// value), those requests will be respected, regardless of this field.
// This field may only be set for services with type LoadBalancer and will
// be cleared if the type is changed to any other type.
// This field is beta-level and is only honored by servers that enable the ServiceLBNodePortControl feature.
// +featureGate=ServiceLBNodePortControl
// +optional
AllocateLoadBalancerNodePorts *bool `json:"allocateLoadBalancerNodePorts,omitempty" protobuf:"bytes,20,opt,name=allocateLoadBalancerNodePorts"`

View File

@ -38,17 +38,14 @@ import (
"k8s.io/apiserver/pkg/admission/plugin/resourcequota"
resourcequotaapi "k8s.io/apiserver/pkg/admission/plugin/resourcequota/apis/resourcequota"
"k8s.io/apiserver/pkg/quota/v1/generic"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
watchtools "k8s.io/client-go/tools/watch"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/controller"
replicationcontroller "k8s.io/kubernetes/pkg/controller/replication"
resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota"
"k8s.io/kubernetes/pkg/features"
quotainstall "k8s.io/kubernetes/pkg/quota/v1/install"
"k8s.io/kubernetes/test/integration/framework"
)
@ -416,7 +413,6 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
}
func TestQuotaLimitService(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)()
// Set up an API server
h := &framework.APIServerHolder{Initialized: make(chan struct{})}

View File

@ -37,7 +37,6 @@ import (
// Test_ServiceLoadBalancerAllocateNodePorts tests that a Service with spec.allocateLoadBalancerNodePorts=false
// does not allocate node ports for the Service.
func Test_ServiceLoadBalancerDisableAllocateNodePorts(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)()
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig()
_, server, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
@ -81,7 +80,6 @@ func Test_ServiceLoadBalancerDisableAllocateNodePorts(t *testing.T) {
// Test_ServiceUpdateLoadBalancerAllocateNodePorts tests that a Service that is updated from ClusterIP to LoadBalancer
// with spec.allocateLoadBalancerNodePorts=false does not allocate node ports for the Service
func Test_ServiceUpdateLoadBalancerDisableAllocateNodePorts(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)()
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig()
_, server, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
@ -135,7 +133,6 @@ func Test_ServiceUpdateLoadBalancerDisableAllocateNodePorts(t *testing.T) {
// Test_ServiceLoadBalancerSwitchToDeallocatedNodePorts test that switching a Service
// to spec.allocateLoadBalancerNodePorts=false, does not de-allocate existing node ports.
func Test_ServiceLoadBalancerEnableThenDisableAllocatedNodePorts(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)()
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig()
_, server, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
@ -189,7 +186,6 @@ func Test_ServiceLoadBalancerEnableThenDisableAllocatedNodePorts(t *testing.T) {
// Test_ServiceLoadBalancerDisableThenEnableAllocatedNodePorts test that switching a Service
// to spec.allocateLoadBalancerNodePorts=true from false, allocate new node ports.
func Test_ServiceLoadBalancerDisableThenEnableAllocatedNodePorts(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)()
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig()
_, server, closeFn := framework.RunAnAPIServer(controlPlaneConfig)