diff --git a/pkg/l4lb/l4controller.go b/pkg/l4lb/l4controller.go index 9ce7ff62ae..b54c84ab0c 100644 --- a/pkg/l4lb/l4controller.go +++ b/pkg/l4lb/l4controller.go @@ -497,10 +497,10 @@ func (l4c *L4Controller) publishMetrics(result *loadbalancers.L4ILBSyncResult, n } switch result.SyncType { case loadbalancers.SyncTypeCreate, loadbalancers.SyncTypeUpdate: - klog.V(6).Infof("Internal L4 Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.MetricsState) + klog.V(2).Infof("Internal L4 Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.MetricsState) l4c.ctx.ControllerMetrics.SetL4ILBService(namespacedName, result.MetricsState) if l4c.enableDualStack { - klog.V(6).Infof("Internal L4 DualStack Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.MetricsState) + klog.V(2).Infof("Internal L4 DualStack Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.DualStackMetricsState) l4c.ctx.ControllerMetrics.SetL4ILBDualStackService(namespacedName, result.DualStackMetricsState) } l4metrics.PublishILBSyncMetrics(result.Error == nil, result.SyncType, result.GCEResourceInError, utils.GetErrorType(result.Error), result.StartTime) @@ -508,10 +508,10 @@ func (l4c *L4Controller) publishMetrics(result *loadbalancers.L4ILBSyncResult, n case loadbalancers.SyncTypeDelete: // if service is successfully deleted, remove it from cache if result.Error == nil { - klog.V(6).Infof("Internal L4 Loadbalancer for Service %s deleted, removing its state from metrics cache", namespacedName) + klog.V(2).Infof("Internal L4 Loadbalancer for Service %s deleted, removing its state from metrics cache", namespacedName) l4c.ctx.ControllerMetrics.DeleteL4ILBService(namespacedName) if l4c.enableDualStack { - klog.V(6).Infof("Internal L4 DualStack LoadBalancer for Service %s deleted, removing its state from metrics cache", namespacedName) + klog.V(2).Infof("Internal L4 DualStack LoadBalancer for Service %s deleted, removing its state from metrics cache", namespacedName) l4c.ctx.ControllerMetrics.DeleteL4ILBDualStackService(namespacedName) } } diff --git a/pkg/l4lb/l4netlbcontroller.go b/pkg/l4lb/l4netlbcontroller.go index 89af3ad505..411e094e40 100644 --- a/pkg/l4lb/l4netlbcontroller.go +++ b/pkg/l4lb/l4netlbcontroller.go @@ -633,14 +633,22 @@ func (lc *L4NetLBController) publishMetrics(result *loadbalancers.L4NetLBSyncRes namespacedName := types.NamespacedName{Name: name, Namespace: namespace}.String() switch result.SyncType { case loadbalancers.SyncTypeCreate, loadbalancers.SyncTypeUpdate: - klog.V(4).Infof("External L4 Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.MetricsState) + klog.V(2).Infof("External L4 Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.MetricsState) lc.ctx.ControllerMetrics.SetL4NetLBService(namespacedName, result.MetricsState) + if lc.enableDualStack { + klog.V(2).Infof("External L4 DualStack Loadbalancer for Service %s ensured, updating its state %v in metrics cache", namespacedName, result.DualStackMetricsState) + lc.ctx.ControllerMetrics.SetL4NetLBDualStackService(namespacedName, result.DualStackMetricsState) + } lc.publishSyncMetrics(result) case loadbalancers.SyncTypeDelete: // if service is successfully deleted, remove it from cache if result.Error == nil { - klog.V(4).Infof("External L4 Loadbalancer for Service %s deleted, removing its state from metrics cache", namespacedName) + klog.V(2).Infof("External L4 Loadbalancer for Service %s deleted, removing its state from metrics cache", namespacedName) lc.ctx.ControllerMetrics.DeleteL4NetLBService(namespacedName) + if lc.enableDualStack { + klog.V(2).Infof("External L4 Loadbalancer for Service %s deleted, removing its state from metrics cache", namespacedName) + lc.ctx.ControllerMetrics.DeleteL4NetLBDualStackService(namespacedName) + } } lc.publishSyncMetrics(result) default: diff --git a/pkg/loadbalancers/l4.go b/pkg/loadbalancers/l4.go index 7abf525c53..579cab3cc0 100644 --- a/pkg/loadbalancers/l4.go +++ b/pkg/loadbalancers/l4.go @@ -65,7 +65,7 @@ type L4ILBSyncResult struct { GCEResourceInError string Status *corev1.LoadBalancerStatus MetricsState metrics.L4ILBServiceState - DualStackMetricsState metrics.L4ILBDualStackServiceState + DualStackMetricsState metrics.L4DualStackServiceState SyncType string StartTime time.Time } @@ -287,7 +287,7 @@ func (l4 *L4) EnsureInternalLoadBalancer(nodeNames []string, svc *corev1.Service Annotations: make(map[string]string), StartTime: time.Now(), SyncType: SyncTypeCreate, - DualStackMetricsState: l4.getInitialDualStackMetricsState(), + DualStackMetricsState: metrics.InitServiceDualStackMetricsState(svc), } // If service already has an IP assigned, treat it as an update instead of a new Loadbalancer. @@ -534,26 +534,6 @@ func (l4 *L4) hasAnnotation(annotationKey string) bool { return false } -func (l4 *L4) getInitialDualStackMetricsState() metrics.L4ILBDualStackServiceState { - // Always init stats with error, and update with Success when service was provisioned - state := metrics.L4ILBDualStackServiceState{ - Status: metrics.StatusError, - } - - var ipFamiliesStrings []string - for _, ipFamily := range l4.Service.Spec.IPFamilies { - ipFamiliesStrings = append(ipFamiliesStrings, string(ipFamily)) - } - state.IPFamilies = strings.Join(ipFamiliesStrings, ",") - - state.IPFamilyPolicy = "" - if l4.Service.Spec.IPFamilyPolicy != nil { - state.IPFamilyPolicy = string(*l4.Service.Spec.IPFamilyPolicy) - } - - return state -} - func (l4 *L4) getOldForwardingRule() (*composite.ForwardingRule, error) { bsName := l4.namer.L4Backend(l4.Service.Namespace, l4.Service.Name) // Check if protocol has changed for this service. In this case, forwarding rule has different protocol and name diff --git a/pkg/loadbalancers/l4netlb.go b/pkg/loadbalancers/l4netlb.go index 2393c28695..92c9c0e13a 100644 --- a/pkg/loadbalancers/l4netlb.go +++ b/pkg/loadbalancers/l4netlb.go @@ -57,22 +57,25 @@ type L4NetLB struct { // L4NetLBSyncResult contains information about the outcome of an L4 NetLB sync. It stores the list of resource name annotations, // sync error, the GCE resource that hit the error along with the error type, metrics and more fields. type L4NetLBSyncResult struct { - Annotations map[string]string - Error error - GCEResourceInError string - Status *corev1.LoadBalancerStatus - MetricsState metrics.L4NetLBServiceState - SyncType string - StartTime time.Time + Annotations map[string]string + Error error + GCEResourceInError string + Status *corev1.LoadBalancerStatus + MetricsState metrics.L4NetLBServiceState + DualStackMetricsState metrics.L4DualStackServiceState + SyncType string + StartTime time.Time } -func NewL4SyncResult(syncType string) *L4NetLBSyncResult { +func NewL4SyncResult(syncType string, svc *corev1.Service) *L4NetLBSyncResult { + startTime := time.Now() result := &L4NetLBSyncResult{ - Annotations: make(map[string]string), - StartTime: time.Now(), - SyncType: syncType, + Annotations: make(map[string]string), + StartTime: startTime, + SyncType: syncType, + MetricsState: metrics.InitL4NetLBServiceState(&startTime), + DualStackMetricsState: metrics.InitServiceDualStackMetricsState(svc), } - result.MetricsState = metrics.InitL4NetLBServiceState(&result.StartTime) return result } @@ -80,6 +83,7 @@ func NewL4SyncResult(syncType string) *L4NetLBSyncResult { func (r *L4NetLBSyncResult) SetMetricsForSuccessfulServiceSync() { r.MetricsState.FirstSyncErrorTime = nil r.MetricsState.InSuccess = true + r.DualStackMetricsState.Status = metrics.StatusSuccess } type L4NetLBParams struct { @@ -117,7 +121,7 @@ func (l4netlb *L4NetLB) createKey(name string) (*meta.Key, error) { // It returns a LoadBalancerStatus with the updated ForwardingRule IP address. // This function does not link instances to Backend Service. func (l4netlb *L4NetLB) EnsureFrontend(nodeNames []string, svc *corev1.Service) *L4NetLBSyncResult { - result := NewL4SyncResult(SyncTypeCreate) + result := NewL4SyncResult(SyncTypeCreate, svc) // If service already has an IP assigned, treat it as an update instead of a new Loadbalancer. if len(svc.Status.LoadBalancer.Ingress) > 0 { result.SyncType = SyncTypeUpdate @@ -281,7 +285,7 @@ func (l4netlb *L4NetLB) ensureIPv4NodesFirewall(nodeNames []string, ipAddress st // EnsureLoadBalancerDeleted performs a cleanup of all GCE resources for the given loadbalancer service. // It is health check, firewall rules and backend service func (l4netlb *L4NetLB) EnsureLoadBalancerDeleted(svc *corev1.Service) *L4NetLBSyncResult { - result := NewL4SyncResult(SyncTypeDelete) + result := NewL4SyncResult(SyncTypeDelete, svc) l4netlb.Service = svc l4netlb.deleteIPv4ResourcesOnDelete(result) diff --git a/pkg/metrics/l4metrics_test.go b/pkg/metrics/l4metrics_test.go index be7759f93e..bec58b8734 100644 --- a/pkg/metrics/l4metrics_test.go +++ b/pkg/metrics/l4metrics_test.go @@ -379,6 +379,76 @@ func TestComputeL4NetLBMetrics(t *testing.T) { } } +func TestComputeL4NetLBDualStackMetrics(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + desc string + serviceStates []L4DualStackServiceState + expectL4NetLBDualStackCount map[L4DualStackServiceState]int + }{ + { + desc: "empty input", + serviceStates: []L4DualStackServiceState{}, + expectL4NetLBDualStackCount: map[L4DualStackServiceState]int{}, + }, + { + desc: "one l4 NetLB dual-stack service", + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4", "SingleStack", StatusSuccess), + }, + expectL4NetLBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4", "SingleStack", StatusSuccess}: 1, + }, + }, + { + desc: "l4 NetLB dual-stack service in error state", + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4", "SingleStack", StatusError), + }, + expectL4NetLBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4", "SingleStack", StatusError}: 1, + }, + }, + { + desc: "L4 NetLB dual-stack service with IPv4,IPv6 Families", + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), + }, + expectL4NetLBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4,IPv6", "RequireDualStack", StatusSuccess}: 1, + }, + }, + { + desc: "many l4 NetLB dual-stack services", + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), + newL4DualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), + newL4DualStackServiceState("IPv4", "SingleStack", StatusError), + newL4DualStackServiceState("IPv6", "SingleStack", StatusSuccess), + newL4DualStackServiceState("IPv6", "SingleStack", StatusSuccess), + }, + expectL4NetLBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4,IPv6", "RequireDualStack", StatusSuccess}: 2, + L4DualStackServiceState{"IPv4", "SingleStack", StatusError}: 1, + L4DualStackServiceState{"IPv6", "SingleStack", StatusSuccess}: 2, + }, + }, + } { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + newMetrics := FakeControllerMetrics() + for i, serviceState := range tc.serviceStates { + newMetrics.SetL4NetLBDualStackService(fmt.Sprint(i), serviceState) + } + got := newMetrics.computeL4NetLBDualStackMetrics() + if diff := cmp.Diff(tc.expectL4NetLBDualStackCount, got); diff != "" { + t.Fatalf("Got diff for L4 NetLB Dual-Stack service counts (-want +got):\n%s", diff) + } + }) + } +} + func newL4NetLBServiceState(inSuccess, managed, premium, userError bool, errorTimestamp *time.Time) L4NetLBServiceState { return L4NetLBServiceState{ IsPremiumTier: premium, @@ -435,78 +505,54 @@ func TestComputeL4ILBDualStackMetrics(t *testing.T) { t.Parallel() for _, tc := range []struct { desc string - serviceStates []L4ILBDualStackServiceState - expectL4ILBDualStackCount map[L4ILBDualStackServiceState]int + serviceStates []L4DualStackServiceState + expectL4ILBDualStackCount map[L4DualStackServiceState]int }{ { desc: "empty input", - serviceStates: []L4ILBDualStackServiceState{}, - expectL4ILBDualStackCount: map[L4ILBDualStackServiceState]int{}, + serviceStates: []L4DualStackServiceState{}, + expectL4ILBDualStackCount: map[L4DualStackServiceState]int{}, }, { desc: "one l4 ilb dual-stack service", - serviceStates: []L4ILBDualStackServiceState{ - newL4ILBDualStackServiceState("IPv4", "SingleStack", StatusSuccess), + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4", "SingleStack", StatusSuccess), }, - expectL4ILBDualStackCount: map[L4ILBDualStackServiceState]int{ - L4ILBDualStackServiceState{ - "IPv4", - "SingleStack", - StatusSuccess, - }: 1, + expectL4ILBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4", "SingleStack", StatusSuccess}: 1, }, }, { desc: "l4 ilb dual-stack service in error state", - serviceStates: []L4ILBDualStackServiceState{ - newL4ILBDualStackServiceState("IPv4", "SingleStack", StatusError), + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4", "SingleStack", StatusError), }, - expectL4ILBDualStackCount: map[L4ILBDualStackServiceState]int{ - L4ILBDualStackServiceState{ - "IPv4", - "SingleStack", - StatusError, - }: 1, + expectL4ILBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4", "SingleStack", StatusError}: 1, }, }, { desc: "L4 ILB dual-stack service with IPv4,IPv6 Families", - serviceStates: []L4ILBDualStackServiceState{ - newL4ILBDualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), }, - expectL4ILBDualStackCount: map[L4ILBDualStackServiceState]int{ - L4ILBDualStackServiceState{ - "IPv4,IPv6", - "RequireDualStack", - StatusSuccess, - }: 1, + expectL4ILBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4,IPv6", "RequireDualStack", StatusSuccess}: 1, }, }, { desc: "many l4 ilb dual-stack services", - serviceStates: []L4ILBDualStackServiceState{ - newL4ILBDualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), - newL4ILBDualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), - newL4ILBDualStackServiceState("IPv4", "SingleStack", StatusError), - newL4ILBDualStackServiceState("IPv6", "SingleStack", StatusSuccess), - newL4ILBDualStackServiceState("IPv6", "SingleStack", StatusSuccess), - }, - expectL4ILBDualStackCount: map[L4ILBDualStackServiceState]int{ - L4ILBDualStackServiceState{ - "IPv4,IPv6", - "RequireDualStack", - StatusSuccess, - }: 2, - L4ILBDualStackServiceState{ - "IPv4", - "SingleStack", - StatusError, - }: 1, - L4ILBDualStackServiceState{ - "IPv6", - "SingleStack", - StatusSuccess, - }: 2, + serviceStates: []L4DualStackServiceState{ + newL4DualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), + newL4DualStackServiceState("IPv4,IPv6", "RequireDualStack", StatusSuccess), + newL4DualStackServiceState("IPv4", "SingleStack", StatusError), + newL4DualStackServiceState("IPv6", "SingleStack", StatusSuccess), + newL4DualStackServiceState("IPv6", "SingleStack", StatusSuccess), + }, + expectL4ILBDualStackCount: map[L4DualStackServiceState]int{ + L4DualStackServiceState{"IPv4,IPv6", "RequireDualStack", StatusSuccess}: 2, + L4DualStackServiceState{"IPv4", "SingleStack", StatusError}: 1, + L4DualStackServiceState{"IPv6", "SingleStack", StatusSuccess}: 2, }, }, } { @@ -525,8 +571,8 @@ func TestComputeL4ILBDualStackMetrics(t *testing.T) { } } -func newL4ILBDualStackServiceState(ipFamilies string, ipFamilyPolicy string, status L4ILBDualStackServiceStateStatus) L4ILBDualStackServiceState { - return L4ILBDualStackServiceState{ +func newL4DualStackServiceState(ipFamilies string, ipFamilyPolicy string, status L4DualStackServiceStatus) L4DualStackServiceState { + return L4DualStackServiceState{ IPFamilies: ipFamilies, IPFamilyPolicy: ipFamilyPolicy, Status: status, diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index a6201ef746..a6963ec4a1 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -19,10 +19,12 @@ package metrics import ( "fmt" "os" + "strings" "sync" "time" "github.com/prometheus/client_golang/prometheus" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/util/wait" frontendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1" @@ -76,6 +78,13 @@ var ( }, []string{"ip_families", "ip_family_policy", "status"}, ) + l4NetLBDualStackCount = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "number_of_l4_dual_stack_netlbs", + Help: "Number of L4 NetLBs with DualStack enabled", + }, + []string{"ip_families", "ip_family_policy", "status"}, + ) l4NetLBCount = prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: "number_of_l4_netlbs", @@ -140,6 +149,9 @@ func init() { klog.V(3).Infof("Registering L4 NetLB usage metrics %v", l4NetLBCount) prometheus.MustRegister(l4NetLBCount) + klog.V(3).Infof("Registering L4 NetLB Dual Stack usage metrics %v", l4NetLBDualStackCount) + prometheus.MustRegister(l4NetLBDualStackCount) + klog.V(3).Infof("Registering PSC usage metrics %v", serviceAttachmentCount) prometheus.MustRegister(serviceAttachmentCount) prometheus.MustRegister(serviceCount) @@ -164,9 +176,11 @@ type ControllerMetrics struct { // l4ILBServiceMap is a map between service key and L4 ILB service state. l4ILBServiceMap map[string]L4ILBServiceState // l4ILBDualStackServiceMap is a map between service key and L4 ILB DualStack service state. - l4ILBDualStackServiceMap map[string]L4ILBDualStackServiceState + l4ILBDualStackServiceMap map[string]L4DualStackServiceState // l4NetLBServiceMap is a map between service key and L4 NetLB service state. l4NetLBServiceMap map[string]L4NetLBServiceState + // l4NetLBDualStackServiceMap is a map between service key and L4 NetLB DualStack service state. + l4NetLBDualStackServiceMap map[string]L4DualStackServiceState // pscMap is a map between the service attachment key and PSC state pscMap map[string]pscmetrics.PSCState // ServiceMap track the number of services in this cluster @@ -182,15 +196,16 @@ type ControllerMetrics struct { // NewControllerMetrics initializes ControllerMetrics and starts a go routine to compute and export metrics periodically. func NewControllerMetrics(exportInterval, l4NetLBProvisionDeadline time.Duration) *ControllerMetrics { return &ControllerMetrics{ - ingressMap: make(map[string]IngressState), - negMap: make(map[string]NegServiceState), - l4ILBServiceMap: make(map[string]L4ILBServiceState), - l4ILBDualStackServiceMap: make(map[string]L4ILBDualStackServiceState), - l4NetLBServiceMap: make(map[string]L4NetLBServiceState), - pscMap: make(map[string]pscmetrics.PSCState), - serviceMap: make(map[string]struct{}), - metricsInterval: exportInterval, - l4NetLBProvisionDeadline: l4NetLBProvisionDeadline, + ingressMap: make(map[string]IngressState), + negMap: make(map[string]NegServiceState), + l4ILBServiceMap: make(map[string]L4ILBServiceState), + l4ILBDualStackServiceMap: make(map[string]L4DualStackServiceState), + l4NetLBServiceMap: make(map[string]L4NetLBServiceState), + l4NetLBDualStackServiceMap: make(map[string]L4DualStackServiceState), + pscMap: make(map[string]pscmetrics.PSCState), + serviceMap: make(map[string]struct{}), + metricsInterval: exportInterval, + l4NetLBProvisionDeadline: l4NetLBProvisionDeadline, } } @@ -286,7 +301,7 @@ func (im *ControllerMetrics) DeleteL4ILBService(svcKey string) { } // SetL4ILBDualStackService implements L4ILBMetricsCollector. -func (im *ControllerMetrics) SetL4ILBDualStackService(svcKey string, state L4ILBDualStackServiceState) { +func (im *ControllerMetrics) SetL4ILBDualStackService(svcKey string, state L4DualStackServiceState) { im.Lock() defer im.Unlock() @@ -330,6 +345,25 @@ func (im *ControllerMetrics) DeleteL4NetLBService(svcKey string) { delete(im.l4NetLBServiceMap, svcKey) } +// SetL4NetLBDualStackService implements L4NetLBMetricsCollector. +func (im *ControllerMetrics) SetL4NetLBDualStackService(svcKey string, state L4DualStackServiceState) { + im.Lock() + defer im.Unlock() + + if im.l4NetLBDualStackServiceMap == nil { + klog.Fatalf("L4 NetLB DualStack Metrics failed to initialize correctly.") + } + im.l4NetLBDualStackServiceMap[svcKey] = state +} + +// DeleteL4NetLBDualStackService implements L4NetLBMetricsCollector. +func (im *ControllerMetrics) DeleteL4NetLBDualStackService(svcKey string) { + im.Lock() + defer im.Unlock() + + delete(im.l4NetLBDualStackServiceMap, svcKey) +} + // SetServiceAttachment adds sa state to the map to be counted during metrics computation. // SetServiceAttachment implements PSCMetricsCollector. func (im *ControllerMetrics) SetServiceAttachment(saKey string, state pscmetrics.PSCState) { @@ -415,6 +449,17 @@ func (im *ControllerMetrics) export() { klog.V(3).Infof("L4 NetLB usage metrics exported.") + netlbDualStackCount := im.computeL4NetLBDualStackMetrics() + klog.V(3).Infof("Exporting L4 NetLB DualStack usage metrics: %#v", netlbDualStackCount) + for state, count := range netlbDualStackCount { + l4NetLBDualStackCount.With(prometheus.Labels{ + "ip_families": state.IPFamilies, + "ip_family_policy": state.IPFamilyPolicy, + "status": string(state.Status), + }).Set(float64(count)) + } + klog.V(3).Infof("L4 Netlb DualStack usage metrics exported.") + saCount := im.computePSCMetrics() klog.V(3).Infof("Exporting PSC Usage Metrics: %#v", saCount) for feature, count := range saCount { @@ -568,11 +613,11 @@ func (im *ControllerMetrics) computeL4ILBMetrics() map[feature]int { } // computeL4ILBDualStackMetrics aggregates L4 ILB DualStack metrics in the cache. -func (im *ControllerMetrics) computeL4ILBDualStackMetrics() map[L4ILBDualStackServiceState]int { +func (im *ControllerMetrics) computeL4ILBDualStackMetrics() map[L4DualStackServiceState]int { im.Lock() defer im.Unlock() klog.V(4).Infof("Computing L4 DualStack ILB usage metrics from service state map: %#v", im.l4ILBDualStackServiceMap) - counts := map[L4ILBDualStackServiceState]int{} + counts := map[L4DualStackServiceState]int{} for key, state := range im.l4ILBDualStackServiceMap { klog.V(6).Infof("ILB Service %s has IPFamilies: %v, IPFamilyPolicy: %t, Status: %v", key, state.IPFamilies, state.IPFamilyPolicy, state.Status) @@ -616,6 +661,21 @@ func (im *ControllerMetrics) computeL4NetLBMetrics() netLBFeatureCount { return counts } +// computeL4NetLBDualStackMetrics aggregates L4 NetLB DualStack metrics in the cache. +func (im *ControllerMetrics) computeL4NetLBDualStackMetrics() map[L4DualStackServiceState]int { + im.Lock() + defer im.Unlock() + klog.V(4).Infof("Computing L4 DualStack NetLB usage metrics from service state map: %#v", im.l4NetLBDualStackServiceMap) + counts := map[L4DualStackServiceState]int{} + + for key, state := range im.l4NetLBDualStackServiceMap { + klog.V(6).Infof("NetLB Service %s has IPFamilies: %v, IPFamilyPolicy: %t, Status: %v", key, state.IPFamilies, state.IPFamilyPolicy, state.Status) + counts[state]++ + } + klog.V(4).Info("L4 NetLB usage metrics computed.") + return counts +} + func (im *ControllerMetrics) computePSCMetrics() map[feature]int { im.Lock() defer im.Unlock() @@ -724,3 +784,22 @@ func recordComponentVersion() { } componentVersion.WithLabelValues(v).Set(versionValue) } + +func InitServiceDualStackMetricsState(svc *corev1.Service) L4DualStackServiceState { + state := L4DualStackServiceState{} + + var ipFamiliesStrings []string + for _, ipFamily := range svc.Spec.IPFamilies { + ipFamiliesStrings = append(ipFamiliesStrings, string(ipFamily)) + } + state.IPFamilies = strings.Join(ipFamiliesStrings, ",") + + state.IPFamilyPolicy = "" + if svc.Spec.IPFamilyPolicy != nil { + state.IPFamilyPolicy = string(*svc.Spec.IPFamilyPolicy) + } + + // Always init status with error, and update with Success when service was provisioned + state.Status = StatusError + return state +} diff --git a/pkg/metrics/types.go b/pkg/metrics/types.go index 5eb825abaa..14bd1b9369 100644 --- a/pkg/metrics/types.go +++ b/pkg/metrics/types.go @@ -73,21 +73,21 @@ type L4ILBServiceState struct { IsUserError bool } -type L4ILBDualStackServiceStateStatus string +type L4DualStackServiceStatus string -const StatusSuccess = L4ILBDualStackServiceStateStatus("Success") -const StatusUserError = L4ILBDualStackServiceStateStatus("UserError") -const StatusError = L4ILBDualStackServiceStateStatus("Error") +const StatusSuccess = L4DualStackServiceStatus("Success") +const StatusUserError = L4DualStackServiceStatus("UserError") +const StatusError = L4DualStackServiceStatus("Error") -// L4ILBDualStackServiceState defines ipFamilies, ipFamilyPolicy and status +// L4DualStackServiceState defines ipFamilies, ipFamilyPolicy and status // of L4 ILB DualStack service -type L4ILBDualStackServiceState struct { +type L4DualStackServiceState struct { // IPFamilies stores spec.ipFamilies of Service IPFamilies string // IPFamilyPolicy specifies spec.IPFamilyPolicy of Service IPFamilyPolicy string - // Status specifies status of L4 ILB DualStack - Status L4ILBDualStackServiceStateStatus + // Status specifies status of L4 DualStack Service + Status L4DualStackServiceStatus } // L4NetLBServiceState defines if network tier is premium and