Merge pull request #34094 from nebril/hless-to-nonhless-ip

Automatic merge from submit-queue

Deny service ClusterIP update from `None`

**What this PR does / why we need it**: Headless service should not be transformed into a service with ClusterIP, therefore update of this field if it's set to `None` is disallowed.

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #33029

**Release note**:
```release-note
Changing service ClusterIP from `None` is not allowed anymore.
```
This commit is contained in:
Kubernetes Submit Queue 2016-10-21 14:34:56 -07:00 committed by GitHub
commit bdaf502ff4
3 changed files with 243 additions and 2 deletions

View File

@ -2635,8 +2635,12 @@ func validateServiceAnnotations(service *api.Service, oldService *api.Service) (
func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
if api.IsServiceIPSet(oldService) {
allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, field.NewPath("spec", "clusterIP"))...)
// ClusterIP should be immutable for services using it (every type other than ExternalName)
// which do not have ClusterIP assigned yet (empty string value)
if service.Spec.Type != api.ServiceTypeExternalName {
if oldService.Spec.Type != api.ServiceTypeExternalName && oldService.Spec.ClusterIP != "" {
allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, field.NewPath("spec", "clusterIP"))...)
}
}
// TODO(freehan): allow user to update loadbalancerSourceRanges

View File

@ -6519,6 +6519,242 @@ func TestValidateServiceUpdate(t *testing.T) {
},
numErrs: 0,
},
{
name: "`None` ClusterIP cannot be changed",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.ClusterIP = "None"
newSvc.Spec.ClusterIP = "1.2.3.4"
},
numErrs: 1,
},
{
name: "`None` ClusterIP cannot be removed",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.ClusterIP = "None"
newSvc.Spec.ClusterIP = ""
},
numErrs: 1,
},
{
name: "Service with ClusterIP type cannot change its set ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeClusterIP
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with ClusterIP type can change its empty ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeClusterIP
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with ClusterIP type cannot change its set ClusterIP when changing type to NodePort",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeClusterIP
newSvc.Spec.Type = api.ServiceTypeNodePort
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with ClusterIP type can change its empty ClusterIP when changing type to NodePort",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeClusterIP
newSvc.Spec.Type = api.ServiceTypeNodePort
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with ClusterIP type cannot change its ClusterIP when changing type to LoadBalancer",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeClusterIP
newSvc.Spec.Type = api.ServiceTypeLoadBalancer
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with ClusterIP type can change its empty ClusterIP when changing type to LoadBalancer",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeClusterIP
newSvc.Spec.Type = api.ServiceTypeLoadBalancer
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with NodePort type cannot change its set ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeNodePort
newSvc.Spec.Type = api.ServiceTypeNodePort
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with NodePort type can change its empty ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeNodePort
newSvc.Spec.Type = api.ServiceTypeNodePort
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with NodePort type cannot change its set ClusterIP when changing type to ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeNodePort
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with NodePort type can change its empty ClusterIP when changing type to ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeNodePort
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with NodePort type cannot change its set ClusterIP when changing type to LoadBalancer",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeNodePort
newSvc.Spec.Type = api.ServiceTypeLoadBalancer
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with NodePort type can change its empty ClusterIP when changing type to LoadBalancer",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeNodePort
newSvc.Spec.Type = api.ServiceTypeLoadBalancer
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with LoadBalancer type cannot change its set ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeLoadBalancer
newSvc.Spec.Type = api.ServiceTypeLoadBalancer
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with LoadBalancer type can change its empty ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeLoadBalancer
newSvc.Spec.Type = api.ServiceTypeLoadBalancer
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with LoadBalancer type cannot change its set ClusterIP when changing type to ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeLoadBalancer
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with LoadBalancer type can change its empty ClusterIP when changing type to ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeLoadBalancer
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with LoadBalancer type cannot change its set ClusterIP when changing type to NodePort",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeLoadBalancer
newSvc.Spec.Type = api.ServiceTypeNodePort
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 1,
},
{
name: "Service with LoadBalancer type can change its empty ClusterIP when changing type to NodePort",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeLoadBalancer
newSvc.Spec.Type = api.ServiceTypeNodePort
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with ExternalName type can change its empty ClusterIP when changing type to ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeExternalName
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = ""
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
{
name: "Service with ExternalName type can change its set ClusterIP when changing type to ClusterIP",
tweakSvc: func(oldSvc, newSvc *api.Service) {
oldSvc.Spec.Type = api.ServiceTypeExternalName
newSvc.Spec.Type = api.ServiceTypeClusterIP
oldSvc.Spec.ClusterIP = "1.2.3.4"
newSvc.Spec.ClusterIP = "1.2.3.5"
},
numErrs: 0,
},
}
for _, tc := range testCases {

View File

@ -100,6 +100,7 @@ func TestUpdate(t *testing.T) {
object := obj.(*api.Service)
object.Spec = api.ServiceSpec{
Selector: map[string]string{"bar": "baz2"},
ClusterIP: "None",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
Ports: []api.ServicePort{{