Skip to content

Commit

Permalink
capacity metrics
Browse files Browse the repository at this point in the history
This adds gauges that describe how many objects the
external-provisioner manages, how many of those already exist, and how
many are to be deleted. Example:

  # HELP csistoragecapacities_desired_current [ALPHA] Number of CSIStorageCapacity objects that exist and are supposed to be managed automatically.
  # TYPE csistoragecapacities_desired_current gauge
  csistoragecapacities_desired_current 2
  # HELP csistoragecapacities_desired_goal [ALPHA] Number of CSIStorageCapacity objects that are supposed to be managed automatically.
  # TYPE csistoragecapacities_desired_goal gauge
  csistoragecapacities_desired_goal 2
  # HELP csistoragecapacities_obsolete [ALPHA] Number of CSIStorageCapacity objects that exist and will be deleted automatically.
  # TYPE csistoragecapacities_obsolete gauge
  csistoragecapacities_obsolete 0
  • Loading branch information
pohly committed Mar 10, 2021
1 parent 14db1ee commit 24e5a70
Show file tree
Hide file tree
Showing 14 changed files with 1,840 additions and 9 deletions.
1 change: 1 addition & 0 deletions cmd/csi-provisioner/csi-provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ func main() {
*capacityPollInterval,
*capacityImmediateBinding,
)
legacyregistry.CustomMustRegister(capacityController)
}

// Start HTTP server, regardless whether we are the leader or not.
Expand Down
3 changes: 1 addition & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/container-storage-interface/spec v1.3.0 h1:wMH4UIoWnK/TXYw8mbcIHgZmB6kHOeIsYsiaTJwa6bc=
github.com/container-storage-interface/spec v1.3.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
Expand Down Expand Up @@ -220,7 +221,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.3.0 h1:q4c+kbcR0d5rSurhBR8dIgieOaYpXtsdTYfx22Cu6rs=
github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
Expand Down Expand Up @@ -1163,7 +1163,6 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.5.0 h1:8mOnjf1RmUPW6KRqQCfYSZq/K20Unmp3IhuZUhxl8KI=
k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
Expand Down
111 changes: 109 additions & 2 deletions pkg/capacity/capacity.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"k8s.io/component-base/metrics"
"k8s.io/klog/v2"
)

Expand Down Expand Up @@ -73,6 +74,8 @@ const (
// and storage class name as some other object. That should never happen,
// but the controller is prepared to clean that up, just in case.
type Controller struct {
metrics.BaseStableCollector

csiController CSICapacityClient
driverName string
client kubernetes.Interface
Expand Down Expand Up @@ -107,6 +110,28 @@ var (
Factor: 1.1,
Steps: 10,
}

objectsGoalDesc = metrics.NewDesc(
"csistoragecapacities_desired_goal",
"Number of CSIStorageCapacity objects that are supposed to be managed automatically.",
nil, nil,
metrics.ALPHA,
"",
)
objectsCurrentDesc = metrics.NewDesc(
"csistoragecapacities_desired_current",
"Number of CSIStorageCapacity objects that exist and are supposed to be managed automatically.",
nil, nil,
metrics.ALPHA,
"",
)
objectsObsoleteDesc = metrics.NewDesc(
"csistoragecapacities_obsolete",
"Number of CSIStorageCapacity objects that exist and will be deleted automatically.",
nil, nil,
metrics.ALPHA,
"",
)
)

// CSICapacityClient is the relevant subset of csi.ControllerClient.
Expand All @@ -115,6 +140,8 @@ type CSICapacityClient interface {
}

// NewController creates a new controller for CSIStorageCapacity objects.
// It implements metrics.StableCollector and thus can be registered in
// a registry.
func NewCentralCapacityController(
csiController CSICapacityClient,
driverName string,
Expand Down Expand Up @@ -358,8 +385,11 @@ func (c *Controller) addWorkItem(segment *topology.Segment, sc *storagev1.Storag
storageClassName: sc.Name,
}
// Ensure that we have an entry for it...
capacity := c.capacities[item]
c.capacities[item] = capacity
_, found := c.capacities[item]
if !found {
c.capacities[item] = nil
}

// ... and then tell our workers to update
// or create that capacity object.
klog.V(5).Infof("Capacity Controller: enqueuing %+v", item)
Expand Down Expand Up @@ -613,6 +643,83 @@ func (c *Controller) onCDelete(ctx context.Context, capacity *storagev1alpha1.CS
}
}

// DescribeWithStability implements the metrics.StableCollector interface.
func (c *Controller) DescribeWithStability(ch chan<- *metrics.Desc) {
ch <- objectsGoalDesc
ch <- objectsCurrentDesc
ch <- objectsObsoleteDesc
}

// CollectWithStability implements the metrics.StableCollector interface.
func (c *Controller) CollectWithStability(ch chan<- metrics.Metric) {
c.capacitiesLock.Lock()
defer c.capacitiesLock.Unlock()

ch <- metrics.NewLazyConstMetric(objectsGoalDesc,
metrics.GaugeValue,
float64(c.getObjectsGoal()),
)
ch <- metrics.NewLazyConstMetric(objectsCurrentDesc,
metrics.GaugeValue,
float64(c.getObjectsCurrent()),
)
ch <- metrics.NewLazyConstMetric(objectsObsoleteDesc,
metrics.GaugeValue,
float64(c.getObjectsObsolete()),
)
}

// getObjectsGoal is called during metrics gathering and calculates the number
// of CSIStorageCapacity objects which are are meant to
// to exist.
func (c *Controller) getObjectsGoal() int64 {
return int64(len(c.capacities))
}

// getObjectsCurrent is called during metrics gathering and calculates the number
// of CSIStorageCapacity objects which are currently exist and are meant to
// continue to exist.
func (c *Controller) getObjectsCurrent() int64 {
current := int64(0)
for _, capacity := range c.capacities {
if capacity != nil {
current++
}
}
return current
}

// getObsoleteObjects is called during metrics gathering and calculates the number
// of CSIStorageCapacity objects which currently exist (according to our informer)
// and which are no longer needed.
func (c *Controller) getObjectsObsolete() int64 {
obsolete := int64(0)
capacities, _ := c.cInformer.Lister().List(labels.Everything())
if capacities == nil {
// Shouldn't happen, local operation.
return 0
}
for _, capacity := range capacities {
if !c.isControlledByUs(capacity.OwnerReferences) {
continue
}
if c.isObsolete(capacity) {
obsolete++
}
}
return obsolete
}

func (c *Controller) isObsolete(capacity *storagev1alpha1.CSIStorageCapacity) bool {
for item, _ := range c.capacities {
if item.storageClassName == capacity.StorageClassName &&
reflect.DeepEqual(item.segment.GetLabelSelector(), capacity.NodeTopology) {
return false
}
}
return true
}

// isControlledByUs implements the same logic as https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1?tab=doc#IsControlledBy,
// just with the expected owner identified directly with the UID.
func (c *Controller) isControlledByUs(owners []metav1.OwnerReference) bool {
Expand Down
Loading

0 comments on commit 24e5a70

Please sign in to comment.