diff --git a/pkg/ccm/loadbalancer.go b/pkg/ccm/loadbalancer.go index 93f3233..1cfe97e 100644 --- a/pkg/ccm/loadbalancer.go +++ b/pkg/ccm/loadbalancer.go @@ -106,7 +106,7 @@ func (l *LoadBalancer) GetLoadBalancerName(_ context.Context, _ string, service // load balancer is not ready yet (e.g., it is still being provisioned) and // polling at a fixed rate is preferred over backing off exponentially in // order to minimize latency. -func (l *LoadBalancer) EnsureLoadBalancer( +func (l *LoadBalancer) EnsureLoadBalancer( //nolint:gocyclo // not really complex ctx context.Context, clusterName string, service *corev1.Service, @@ -126,7 +126,7 @@ func (l *LoadBalancer) EnsureLoadBalancer( return nil, fmt.Errorf("reconcile metricsRemoteWrite: %w", err) } - spec, events, err := lbSpecFromService(service, nodes, l.networkID, observabilityOptions) + spec, events, err := lbSpecFromService(service, nodes, l.networkID, l.extraLabels, observabilityOptions) if err != nil { return nil, fmt.Errorf("invalid load balancer specification: %w", err) } @@ -137,7 +137,11 @@ func (l *LoadBalancer) EnsureLoadBalancer( fulfills, immutableChanged := compareLBwithSpec(lb, spec) if immutableChanged != nil { - return nil, fmt.Errorf("updated to load balancer cannot be fulfilled. Load balancer API doesn't support changing %q", immutableChanged.field) + changeStr := fmt.Sprintf("%q", immutableChanged.field) + if immutableChanged.annotation != "" { + changeStr += fmt.Sprintf(" (%q)", immutableChanged.annotation) + } + return nil, fmt.Errorf("update to load balancer cannot be fulfilled: API doesn't support changing %s", changeStr) } if !fulfills { credentialsRefBeforeUpdate := getMetricsRemoteWriteRef(lb) @@ -202,7 +206,7 @@ func (l *LoadBalancer) createLoadBalancer(ctx context.Context, clusterName strin return nil, fmt.Errorf("reconcile metricsRemoteWrite: %w", err) } - spec, events, err := lbSpecFromService(service, nodes, l.networkID, metricsRemoteWrite) + spec, events, err := lbSpecFromService(service, nodes, l.networkID, l.extraLabels, metricsRemoteWrite) if err != nil { return nil, fmt.Errorf("invalid load balancer specification: %w", err) } @@ -234,7 +238,7 @@ func (l *LoadBalancer) createLoadBalancer(ctx context.Context, clusterName strin // It is not called on controller start-up. EnsureLoadBalancer must also ensure to update targets. func (l *LoadBalancer) UpdateLoadBalancer(ctx context.Context, clusterName string, service *corev1.Service, nodes []*corev1.Node) error { // only TargetPools are used from spec - spec, events, err := lbSpecFromService(service, nodes, l.networkID, nil) + spec, events, err := lbSpecFromService(service, nodes, l.networkID, l.extraLabels, nil) if err != nil { return fmt.Errorf("invalid service: %w", err) } diff --git a/pkg/ccm/loadbalancer_spec.go b/pkg/ccm/loadbalancer_spec.go index 53bfe8a..a74533f 100644 --- a/pkg/ccm/loadbalancer_spec.go +++ b/pkg/ccm/loadbalancer_spec.go @@ -10,6 +10,7 @@ import ( "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/services/loadbalancer" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "github.com/stackitcloud/cloud-provider-stackit/pkg/cmp" ) @@ -244,6 +245,7 @@ func lbSpecFromService( //nolint:funlen,gocyclo // It is long but not complex. service *corev1.Service, nodes []*corev1.Node, networkID string, + extraLabels map[string]string, observability *loadbalancer.LoadbalancerOptionObservability, ) (*loadbalancer.CreateLoadBalancerPayload, []Event, error) { lb := &loadbalancer.CreateLoadBalancerPayload{ @@ -275,6 +277,14 @@ func lbSpecFromService( //nolint:funlen,gocyclo // It is long but not complex. } } + // Add extraLabels if set + if extraLabels != nil { + lb.Labels = ptr.To(extraLabels) + } + + // Add metric metricsRemoteWrite settings + lb.Options.Observability = observability + events := make([]Event, 0) // Parse private network from annotations. @@ -342,9 +352,6 @@ func lbSpecFromService( //nolint:funlen,gocyclo // It is long but not complex. lb.ExternalAddress = &externalIP } - // Add metric metricsRemoteWrite settings - lb.Options.Observability = observability - // Parse TCP idle timeout from annotations. // TODO: Split into separate function. tcpIdleTimeout := defaultTCPIdleTimeout @@ -576,7 +583,8 @@ func checkUnsupportedAnnotations(service *corev1.Service) *Event { // resultImmutableChanged denotes that at least one property that cannot be changed did change. // Attempting an update will fail. type resultImmutableChanged struct { - field string + field string + annotation string } // compareLBwithSpec checks whether the load balancer fulfills the specification. @@ -587,7 +595,7 @@ func compareLBwithSpec(lb *loadbalancer.LoadBalancer, spec *loadbalancer.CreateL fulfills = true if cmp.UnpackPtr(cmp.UnpackPtr(lb.Options).PrivateNetworkOnly) != cmp.UnpackPtr(cmp.UnpackPtr(spec.Options).PrivateNetworkOnly) { - return false, &resultImmutableChanged{field: ".options.privateNetworkOnly"} + return false, &resultImmutableChanged{field: ".options.privateNetworkOnly", annotation: internalLBAnnotation} } if !cmp.PtrValEqualFn( @@ -620,7 +628,7 @@ func compareLBwithSpec(lb *loadbalancer.LoadBalancer, spec *loadbalancer.CreateL // lb.ExternalAddress is set to the ephemeral IP if the load balancer is ephemeral, while spec will never contain an ephemeral IP. // So we only compare them if the spec has a static IP. if !cmp.PtrValEqual(lb.ExternalAddress, spec.ExternalAddress) { - return false, &resultImmutableChanged{field: ".externalAddress"} + return false, &resultImmutableChanged{field: ".externalAddress", annotation: externalIPAnnotation} } if cmp.UnpackPtr(cmp.UnpackPtr(lb.Options).EphemeralAddress) { // Promote an ephemeral IP to a static IP. @@ -629,7 +637,7 @@ func compareLBwithSpec(lb *loadbalancer.LoadBalancer, spec *loadbalancer.CreateL } else if !cmp.UnpackPtr(cmp.UnpackPtr(lb.Options).PrivateNetworkOnly) && !cmp.UnpackPtr(cmp.UnpackPtr(lb.Options).EphemeralAddress) { // Demotion is not allowed by the load balancer API. - return false, &resultImmutableChanged{field: ".options.ephemeralAddress"} + return false, &resultImmutableChanged{field: ".options.ephemeralAddress", annotation: externalIPAnnotation} } if cmp.LenSlicePtr(lb.Listeners) != cmp.LenSlicePtr(spec.Listeners) { @@ -664,16 +672,16 @@ func compareLBwithSpec(lb *loadbalancer.LoadBalancer, spec *loadbalancer.CreateL } if cmp.LenSlicePtr(lb.Networks) != cmp.LenSlicePtr(spec.Networks) { - return false, &resultImmutableChanged{field: "len(.networks)"} + return false, &resultImmutableChanged{field: "len(.networks)", annotation: listenerNetworkAnnotation} } if cmp.LenSlicePtr(lb.Networks) > 0 { for i, x := range *lb.Networks { y := (*spec.Networks)[i] if !cmp.PtrValEqual(x.NetworkId, y.NetworkId) { - return false, &resultImmutableChanged{field: fmt.Sprintf(".networks[%d].networkId", i)} + return false, &resultImmutableChanged{field: fmt.Sprintf(".networks[%d].networkId", i), annotation: listenerNetworkAnnotation} } if !cmp.PtrValEqual(x.Role, y.Role) { - return false, &resultImmutableChanged{field: fmt.Sprintf(".networks[%d].role", i)} + return false, &resultImmutableChanged{field: fmt.Sprintf(".networks[%d].role", i), annotation: listenerNetworkAnnotation} } } } diff --git a/pkg/ccm/loadbalancer_spec_test.go b/pkg/ccm/loadbalancer_spec_test.go index 059e1a4..bf052ab 100644 --- a/pkg/ccm/loadbalancer_spec_test.go +++ b/pkg/ccm/loadbalancer_spec_test.go @@ -57,7 +57,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/internal-lb": "true", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Options": PointTo(MatchFields(IgnoreExtras, Fields{ @@ -73,7 +73,7 @@ var _ = Describe("lbSpecFromService", func() { "yawol.stackit.cloud/internalLB": "true", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Options": PointTo(MatchFields(IgnoreExtras, Fields{ @@ -89,7 +89,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/internal-lb": "maybe", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("invalid bool"))) }) @@ -101,7 +101,7 @@ var _ = Describe("lbSpecFromService", func() { "yawol.stackit.cloud/internalLB": "false", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("incompatible values"))) }) @@ -114,7 +114,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, } - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, "my-network", nil) + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Options.PrivateNetworkOnly).To(PointTo(BeTrue())) Expect(spec.ExternalAddress).To(BeNil()) @@ -129,7 +129,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/external-address": externalAddress, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.ExternalAddress).To(PointTo(Equal(externalAddress))) }) @@ -141,7 +141,7 @@ var _ = Describe("lbSpecFromService", func() { "yawol.stackit.cloud/existingFloatingIP": externalAddress, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.ExternalAddress).To(PointTo(Equal(externalAddress))) }) @@ -154,7 +154,7 @@ var _ = Describe("lbSpecFromService", func() { "yawol.stackit.cloud/existingFloatingIP": "55.66.77.88", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("incompatible values"))) }) @@ -165,7 +165,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/external-address": "I'm not an IP", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) @@ -176,7 +176,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/external-address": "2001:db8::", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) }) @@ -184,7 +184,7 @@ var _ = Describe("lbSpecFromService", func() { Context("Metric metricsRemoteWrite", func() { It("should set metrics in load balancer spec", func() { pushURL := "test-endpoint" - spec, _, err := lbSpecFromService(&corev1.Service{}, []*corev1.Node{}, "my-network", &loadbalancer.LoadbalancerOptionObservability{ + spec, _, err := lbSpecFromService(&corev1.Service{}, []*corev1.Node{}, "my-network", nil, &loadbalancer.LoadbalancerOptionObservability{ Metrics: &loadbalancer.LoadbalancerOptionMetrics{ CredentialsRef: ptr.To(sampleCredentialsRef), PushUrl: &pushURL, @@ -216,7 +216,7 @@ var _ = Describe("lbSpecFromService", func() { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{http, dns, httpAlt}, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Listeners": PointTo(ConsistOf( @@ -251,7 +251,7 @@ var _ = Describe("lbSpecFromService", func() { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{http, httpAlt, https}, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Listeners": PointTo(ConsistOf( @@ -284,7 +284,7 @@ var _ = Describe("lbSpecFromService", func() { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{http}, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Listeners": PointTo(ConsistOf( @@ -309,7 +309,7 @@ var _ = Describe("lbSpecFromService", func() { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{http}, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("incompatible values"))) }) @@ -325,7 +325,7 @@ var _ = Describe("lbSpecFromService", func() { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{http}, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("invalid port"))) }) @@ -342,7 +342,7 @@ var _ = Describe("lbSpecFromService", func() { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{http}, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("incompatible values"))) }) }) @@ -365,7 +365,7 @@ var _ = Describe("lbSpecFromService", func() { Addresses: []corev1.NodeAddress{{Type: corev1.NodeInternalIP, Address: "10.2.3.4"}}, }, }, - }, "my-network", nil) + }, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -400,7 +400,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("unsupported protocol"))) }) @@ -421,7 +421,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, } - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, "my-network", nil) + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf(havePortName("port-tcp-80")))) Expect(spec).To(haveConsistentTargetPool()) @@ -444,7 +444,7 @@ var _ = Describe("lbSpecFromService", func() { "16.0.0.0/8", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Options": PointTo(MatchFields(IgnoreExtras, Fields{ @@ -463,7 +463,7 @@ var _ = Describe("lbSpecFromService", func() { "yawol.stackit.cloud/loadBalancerSourceRanges": "2.0.0.0/8,3.0.0.0/8", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec).To(PointTo(MatchFields(IgnoreExtras, Fields{ "Options": PointTo(MatchFields(IgnoreExtras, Fields{ @@ -493,7 +493,7 @@ var _ = Describe("lbSpecFromService", func() { Addresses: []corev1.NodeAddress{{Type: corev1.NodeInternalIP, Address: "10.2.3.4"}}, }, }, - }, "my-network", nil) + }, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.TargetPools).To(PointTo(HaveLen(2))) Expect(spec.TargetPools).To(PointTo(HaveEach( @@ -526,7 +526,7 @@ var _ = Describe("lbSpecFromService", func() { Addresses: []corev1.NodeAddress{{Type: corev1.NodeExternalIP, Address: "4.5.6.7"}}, }, }, - }, "my-network", nil) + }, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.TargetPools).To(PointTo(ConsistOf( haveTargets(ConsistOf( // node-2 is missing @@ -549,7 +549,7 @@ var _ = Describe("lbSpecFromService", func() { annotation: "some value", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(events).To(ConsistOf(Event{ Type: corev1.EventTypeWarning, @@ -582,7 +582,7 @@ var _ = Describe("lbSpecFromService", func() { "yawol.stackit.cloud/serverGroupPolicy": "my-policy", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(events).To(ConsistOf(Event{ Type: corev1.EventTypeWarning, @@ -627,7 +627,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -672,7 +672,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -701,7 +701,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -731,7 +731,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) @@ -752,7 +752,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) @@ -773,7 +773,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -803,7 +803,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.PlanId).To(HaveValue(BeEquivalentTo("p250"))) }) @@ -823,7 +823,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) @@ -843,7 +843,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(events).To(HaveLen(1)) //nolint: lll // it needs to match the message in loadbalancer_spec.go @@ -869,7 +869,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(events).To(HaveLen(1)) //nolint: lll // it needs to match the message in loadbalancer_spec.go @@ -894,7 +894,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) }) @@ -926,7 +926,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -964,7 +964,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -993,7 +993,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -1023,7 +1023,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) @@ -1044,7 +1044,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(HaveOccurred()) }) @@ -1065,7 +1065,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Listeners).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -1094,7 +1094,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.TargetPools).To(PointTo(HaveEach( MatchFields(IgnoreExtras, Fields{ @@ -1121,7 +1121,7 @@ var _ = Describe("lbSpecFromService", func() { }, }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.TargetPools).To(PointTo(HaveEach( MatchFields(IgnoreExtras, Fields{ @@ -1139,7 +1139,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/session-persistence-with-source-ip": "foo", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).To(MatchError(ContainSubstring("invalid bool"))) }) }) @@ -1151,7 +1151,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/internal-lb": "true", }, }, - }, []*corev1.Node{}, "my-network", nil) + }, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Networks).To(PointTo(ConsistOf(MatchFields(IgnoreExtras, Fields{ "NetworkId": PointTo(Equal("my-network")), @@ -1166,7 +1166,7 @@ var _ = Describe("lbSpecFromService", func() { "lb.stackit.cloud/listener-network": "my-listener-network", }, }, - }, []*corev1.Node{}, "my-target-network", nil) + }, []*corev1.Node{}, "my-target-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(spec.Networks).To(PointTo(ConsistOf( MatchFields(IgnoreExtras, Fields{ @@ -1181,7 +1181,7 @@ var _ = Describe("lbSpecFromService", func() { }) It("should configure a public service without existing IP as ephemeral", func() { - spec, _, err := lbSpecFromService(&corev1.Service{}, []*corev1.Node{}, "my-network", nil) + spec, _, err := lbSpecFromService(&corev1.Service{}, []*corev1.Node{}, "my-network", nil, nil) Expect(err).NotTo(HaveOccurred()) Expect(*spec.Options.EphemeralAddress).To(BeTrue()) }) @@ -1312,7 +1312,7 @@ var _ = DescribeTable("compareLBwithSpec", }, }), Entry("When LB has no external IP but one is specified", &compareLBwithSpecTest{ - wantImmutabledChanged: &resultImmutableChanged{field: ".externalAddress"}, + wantImmutabledChanged: &resultImmutableChanged{field: ".externalAddress", annotation: externalIPAnnotation}, lb: &loadbalancer.LoadBalancer{ ExternalAddress: nil, }, @@ -1322,7 +1322,7 @@ var _ = DescribeTable("compareLBwithSpec", }), Entry("When specified and actual IP don't match", &compareLBwithSpecTest{ // The IP can never be changed. Not even with promotion or demotion. - wantImmutabledChanged: &resultImmutableChanged{field: ".externalAddress"}, + wantImmutabledChanged: &resultImmutableChanged{field: ".externalAddress", annotation: externalIPAnnotation}, lb: &loadbalancer.LoadBalancer{ ExternalAddress: utils.Ptr("123.124.88.01"), }, @@ -1346,7 +1346,7 @@ var _ = DescribeTable("compareLBwithSpec", }, }), Entry("When IP is to be demoted", &compareLBwithSpecTest{ - wantImmutabledChanged: &resultImmutableChanged{field: ".options.ephemeralAddress"}, + wantImmutabledChanged: &resultImmutableChanged{field: ".options.ephemeralAddress", annotation: externalIPAnnotation}, lb: &loadbalancer.LoadBalancer{ Options: &loadbalancer.LoadBalancerOptions{ EphemeralAddress: utils.Ptr(false), @@ -1542,7 +1542,7 @@ var _ = DescribeTable("compareLBwithSpec", }, }), Entry("When LB has no networks but one is specified", &compareLBwithSpecTest{ - wantImmutabledChanged: &resultImmutableChanged{field: "len(.networks)"}, + wantImmutabledChanged: &resultImmutableChanged{field: "len(.networks)", annotation: listenerNetworkAnnotation}, lb: &loadbalancer.LoadBalancer{ Options: &loadbalancer.LoadBalancerOptions{ PrivateNetworkOnly: utils.Ptr(true), @@ -1559,7 +1559,7 @@ var _ = DescribeTable("compareLBwithSpec", }, }), Entry("When network id doesn't match", &compareLBwithSpecTest{ - wantImmutabledChanged: &resultImmutableChanged{field: ".networks[0].networkId"}, + wantImmutabledChanged: &resultImmutableChanged{field: ".networks[0].networkId", annotation: listenerNetworkAnnotation}, lb: &loadbalancer.LoadBalancer{ Options: &loadbalancer.LoadBalancerOptions{ PrivateNetworkOnly: utils.Ptr(true), @@ -1582,7 +1582,7 @@ var _ = DescribeTable("compareLBwithSpec", }, }), Entry("When network role doesn't match", &compareLBwithSpecTest{ - wantImmutabledChanged: &resultImmutableChanged{field: ".networks[0].role"}, + wantImmutabledChanged: &resultImmutableChanged{field: ".networks[0].role", annotation: listenerNetworkAnnotation}, lb: &loadbalancer.LoadBalancer{ Options: &loadbalancer.LoadBalancerOptions{ PrivateNetworkOnly: utils.Ptr(true), @@ -1858,7 +1858,7 @@ var _ = DescribeTable("compareLBwithSpec", }, }), Entry("When private network is disabled but specified", &compareLBwithSpecTest{ - wantImmutabledChanged: &resultImmutableChanged{field: ".options.privateNetworkOnly"}, + wantImmutabledChanged: &resultImmutableChanged{field: ".options.privateNetworkOnly", annotation: internalLBAnnotation}, lb: &loadbalancer.LoadBalancer{ Options: nil, }, diff --git a/pkg/ccm/loadbalancer_test.go b/pkg/ccm/loadbalancer_test.go index 942993a..e3e4c80 100644 --- a/pkg/ccm/loadbalancer_test.go +++ b/pkg/ccm/loadbalancer_test.go @@ -126,7 +126,7 @@ var _ = Describe("LoadBalancer", func() { DescribeTable("should report status for external LB", func(hasExternalAddress bool) { svc := minimalLoadBalancerService() - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil) + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil, nil) Expect(err).NotTo(HaveOccurred()) myLb := convertToLB(spec) if !hasExternalAddress { @@ -163,7 +163,7 @@ var _ = Describe("LoadBalancer", func() { Type: corev1.ServiceTypeLoadBalancer, }, } - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil) + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil, nil) Expect(err).NotTo(HaveOccurred()) myLb := convertToLB(spec) Expect(myLb.ExternalAddress).To(BeNil()) @@ -224,7 +224,7 @@ var _ = Describe("LoadBalancer", func() { It("should update observability credential if credentials are specified in load balancer", func() { svc := minimalLoadBalancerService() - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, &loadbalancer.LoadbalancerOptionObservability{ + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil, &loadbalancer.LoadbalancerOptionObservability{ Metrics: &loadbalancer.LoadbalancerOptionMetrics{ CredentialsRef: utils.Ptr(sampleCredentialsRef), PushUrl: &lbInModeIgnoreAndObs.metricsRemoteWrite.endpoint, @@ -255,7 +255,7 @@ var _ = Describe("LoadBalancer", func() { It("should update the load balancer if the service changed", func() { svc := minimalLoadBalancerService() - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil) + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil, nil) Expect(err).NotTo(HaveOccurred()) myLb := &loadbalancer.LoadBalancer{ Errors: &[]loadbalancer.LoadBalancerError{}, @@ -313,7 +313,7 @@ var _ = Describe("LoadBalancer", func() { Port: 80, NodePort: 1234, }) - spec, _, err := lbSpecFromService(svc, []*corev1.Node{nodeA}, networkID, nil) + spec, _, err := lbSpecFromService(svc, []*corev1.Node{nodeA}, networkID, nil, nil) Expect(err).NotTo(HaveOccurred()) myLb := &loadbalancer.LoadBalancer{ Errors: &[]loadbalancer.LoadBalancerError{}, @@ -344,7 +344,7 @@ var _ = Describe("LoadBalancer", func() { It("should delete observability credentials and delete reference from load balancer if controller is not configured (monitoring extension disabled)", func() { svc := minimalLoadBalancerService() - spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, &loadbalancer.LoadbalancerOptionObservability{ + spec, _, err := lbSpecFromService(svc, []*corev1.Node{}, networkID, nil, &loadbalancer.LoadbalancerOptionObservability{ Metrics: &loadbalancer.LoadbalancerOptionMetrics{ CredentialsRef: ptr.To(sampleCredentialsRef), PushUrl: ptr.To("test-endpoint"),