diff --git a/staging/src/k8s.io/cloud-provider/controllers/service/controller.go b/staging/src/k8s.io/cloud-provider/controllers/service/controller.go index d470fef7de83..cda635ea4445 100644 --- a/staging/src/k8s.io/cloud-provider/controllers/service/controller.go +++ b/staging/src/k8s.io/cloud-provider/controllers/service/controller.go @@ -582,6 +582,15 @@ func (c *Controller) needsUpdate(oldService *v1.Service, newService *v1.Service) return true } + // User can upgrade (add another clusterIP or ipFamily) or can downgrade (remove secondary clusterIP or ipFamily), + // but CAN NOT change primary/secondary clusterIP || ipFamily UNLESS they are changing from/to/ON ExternalName + // so not care about order, only need check the length. + if len(oldService.Spec.IPFamilies) != len(newService.Spec.IPFamilies) { + c.eventRecorder.Eventf(newService, v1.EventTypeNormal, "IPFamilies", "Count: %v -> %v", + len(oldService.Spec.IPFamilies), len(newService.Spec.IPFamilies)) + return true + } + return false } diff --git a/staging/src/k8s.io/cloud-provider/controllers/service/controller_test.go b/staging/src/k8s.io/cloud-provider/controllers/service/controller_test.go index 77f7050cf59e..2b2aa5f91301 100644 --- a/staging/src/k8s.io/cloud-provider/controllers/service/controller_test.go +++ b/staging/src/k8s.io/cloud-provider/controllers/service/controller_test.go @@ -1633,6 +1633,80 @@ func TestNeedsUpdate(t *testing.T) { }, expectedNeedsUpdate: true, }, + { + testName: "If service IPFamilies from single stack to dual stack", + updateFn: func() { + protocol := "http" + oldSvc = &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-service", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Port: 80, + Protocol: v1.ProtocolTCP, + TargetPort: intstr.Parse("22"), + AppProtocol: &protocol, + }}, + IPFamilies: []v1.IPFamily{v1.IPv4Protocol}, + Type: v1.ServiceTypeLoadBalancer, + }, + } + newSvc = oldSvc.DeepCopy() + newSvc.Spec.IPFamilies = []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol} + }, + expectedNeedsUpdate: true, + }, + { + testName: "If service IPFamilies from dual stack to single stack", + updateFn: func() { + protocol := "http" + oldSvc = &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-service", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Port: 80, + Protocol: v1.ProtocolTCP, + TargetPort: intstr.Parse("22"), + AppProtocol: &protocol, + }}, + IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}, + Type: v1.ServiceTypeLoadBalancer, + }, + } + newSvc = oldSvc.DeepCopy() + newSvc.Spec.IPFamilies = []v1.IPFamily{v1.IPv4Protocol} + }, + expectedNeedsUpdate: true, + }, + { + testName: "If service IPFamilies not change", + updateFn: func() { + protocol := "http" + oldSvc = &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-service", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Port: 80, + Protocol: v1.ProtocolTCP, + TargetPort: intstr.Parse("22"), + AppProtocol: &protocol, + }}, + IPFamilies: []v1.IPFamily{v1.IPv4Protocol}, + Type: v1.ServiceTypeLoadBalancer, + }, + } + newSvc = oldSvc.DeepCopy() + }, + expectedNeedsUpdate: false, + }, } controller, _, _ := newController()