kube-state-metrics/internal/discovery/types.go

116 lines
3.7 KiB
Go

/*
Copyright 2023 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package discovery
import (
"fmt"
"sync"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type groupVersionKindPlural struct {
schema.GroupVersionKind
Plural string
}
func (g groupVersionKindPlural) String() string {
return fmt.Sprintf("%s/%s, Kind=%s, Plural=%s", g.Group, g.Version, g.Kind, g.Plural)
}
type kindPlural struct {
Kind string
Plural string
}
// CRDiscoverer provides a cache of the collected GVKs, along with helper utilities.
type CRDiscoverer struct {
// CRDsAddEventsCounter tracks the number of times that the CRD informer triggered the "add" event.
CRDsAddEventsCounter prometheus.Counter
// CRDsDeleteEventsCounter tracks the number of times that the CRD informer triggered the "remove" event.
CRDsDeleteEventsCounter prometheus.Counter
// CRDsCacheCountGauge tracks the net amount of CRDs affecting the cache at this point.
CRDsCacheCountGauge prometheus.Gauge
// Map is a cache of the collected GVKs.
Map map[string]map[string][]kindPlural
// GVKToReflectorStopChanMap is a map of GVKs to channels that can be used to stop their corresponding reflector.
GVKToReflectorStopChanMap map[string]chan struct{}
// m is a mutex to protect the cache.
m sync.RWMutex
// ShouldUpdate is a flag that indicates whether the cache was updated.
WasUpdated bool
}
// SafeRead executes the given function while holding a read lock.
func (r *CRDiscoverer) SafeRead(f func()) {
r.m.RLock()
defer r.m.RUnlock()
f()
}
// SafeWrite executes the given function while holding a write lock.
func (r *CRDiscoverer) SafeWrite(f func()) {
r.m.Lock()
defer r.m.Unlock()
f()
}
// AppendToMap appends the given GVKs to the cache.
func (r *CRDiscoverer) AppendToMap(gvkps ...groupVersionKindPlural) {
if r.Map == nil {
r.Map = map[string]map[string][]kindPlural{}
}
if r.GVKToReflectorStopChanMap == nil {
r.GVKToReflectorStopChanMap = map[string]chan struct{}{}
}
for _, gvkp := range gvkps {
if _, ok := r.Map[gvkp.Group]; !ok {
r.Map[gvkp.Group] = map[string][]kindPlural{}
}
if _, ok := r.Map[gvkp.Group][gvkp.Version]; !ok {
r.Map[gvkp.Group][gvkp.Version] = []kindPlural{}
}
r.Map[gvkp.Group][gvkp.Version] = append(r.Map[gvkp.Group][gvkp.Version], kindPlural{Kind: gvkp.Kind, Plural: gvkp.Plural})
r.GVKToReflectorStopChanMap[gvkp.GroupVersionKind.String()] = make(chan struct{})
}
}
// RemoveFromMap removes the given GVKs from the cache.
func (r *CRDiscoverer) RemoveFromMap(gvkps ...groupVersionKindPlural) {
for _, gvkp := range gvkps {
if _, ok := r.Map[gvkp.Group]; !ok {
continue
}
if _, ok := r.Map[gvkp.Group][gvkp.Version]; !ok {
continue
}
for i, el := range r.Map[gvkp.Group][gvkp.Version] {
if el.Kind == gvkp.Kind {
close(r.GVKToReflectorStopChanMap[gvkp.GroupVersionKind.String()])
delete(r.GVKToReflectorStopChanMap, gvkp.GroupVersionKind.String())
if len(r.Map[gvkp.Group][gvkp.Version]) == 1 {
delete(r.Map[gvkp.Group], gvkp.Version)
if len(r.Map[gvkp.Group]) == 0 {
delete(r.Map, gvkp.Group)
}
break
}
r.Map[gvkp.Group][gvkp.Version] = append(r.Map[gvkp.Group][gvkp.Version][:i], r.Map[gvkp.Group][gvkp.Version][i+1:]...)
break
}
}
}
}