mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
add version parsing to metrics framework, use build version information for registry version
This commit is contained in:
parent
cebad0da66
commit
abe64acc8d
@ -14,10 +14,13 @@ go_library(
|
||||
"opts.go",
|
||||
"registry.go",
|
||||
"util.go",
|
||||
"version_parser.go",
|
||||
"wrappers.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/util/metrics",
|
||||
deps = [
|
||||
"//pkg/version:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
"//vendor/github.com/blang/semver:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
@ -32,9 +35,11 @@ go_test(
|
||||
"counter_test.go",
|
||||
"registry_test.go",
|
||||
"util_test.go",
|
||||
"version_parser_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
"//vendor/github.com/blang/semver:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
|
@ -33,13 +33,13 @@ type kubeCounter struct {
|
||||
// NewCounter returns an object which satisfies the KubeCollector and KubeCounter interfaces.
|
||||
// However, the object returned will not measure anything unless the collector is first
|
||||
// registered, since the metric is lazily instantiated.
|
||||
func NewCounter(opts CounterOpts) *kubeCounter {
|
||||
func NewCounter(opts *CounterOpts) *kubeCounter {
|
||||
// todo: handle defaulting better
|
||||
if opts.StabilityLevel == "" {
|
||||
opts.StabilityLevel = ALPHA
|
||||
}
|
||||
kc := &kubeCounter{
|
||||
CounterOpts: &opts,
|
||||
CounterOpts: opts,
|
||||
lazyMetric: lazyMetric{},
|
||||
}
|
||||
kc.setPrometheusCounter(noop)
|
||||
@ -85,10 +85,10 @@ type kubeCounterVec struct {
|
||||
// NewCounterVec returns an object which satisfies the KubeCollector and KubeCounterVec interfaces.
|
||||
// However, the object returned will not measure anything unless the collector is first
|
||||
// registered, since the metric is lazily instantiated.
|
||||
func NewCounterVec(opts CounterOpts, labels []string) *kubeCounterVec {
|
||||
func NewCounterVec(opts *CounterOpts, labels []string) *kubeCounterVec {
|
||||
cv := &kubeCounterVec{
|
||||
CounterVec: noopCounterVec,
|
||||
CounterOpts: &opts,
|
||||
CounterOpts: opts,
|
||||
originalLabels: labels,
|
||||
lazyMetric: lazyMetric{},
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ func TestCounter(t *testing.T) {
|
||||
v114 := semver.MustParse("1.14.0")
|
||||
var tests = []struct {
|
||||
desc string
|
||||
CounterOpts
|
||||
*CounterOpts
|
||||
registryVersion *semver.Version
|
||||
expectedMetricCount int
|
||||
expectedHelp string
|
||||
}{
|
||||
{
|
||||
desc: "Test non deprecated",
|
||||
CounterOpts: CounterOpts{
|
||||
CounterOpts: &CounterOpts{
|
||||
Namespace: "namespace",
|
||||
Name: "metric_test_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -48,7 +48,7 @@ func TestCounter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "Test deprecated",
|
||||
CounterOpts: CounterOpts{
|
||||
CounterOpts: &CounterOpts{
|
||||
Namespace: "namespace",
|
||||
Name: "metric_test_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -62,7 +62,7 @@ func TestCounter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "Test hidden",
|
||||
CounterOpts: CounterOpts{
|
||||
CounterOpts: &CounterOpts{
|
||||
Namespace: "namespace",
|
||||
Name: "metric_test_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -77,7 +77,7 @@ func TestCounter(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
registry := NewKubeRegistry(*test.registryVersion)
|
||||
registry := newKubeRegistry(*test.registryVersion)
|
||||
c := NewCounter(test.CounterOpts)
|
||||
registry.MustRegister(c)
|
||||
|
||||
@ -126,7 +126,7 @@ func TestCounterVec(t *testing.T) {
|
||||
v114 := semver.MustParse("1.14.0")
|
||||
var tests = []struct {
|
||||
desc string
|
||||
CounterOpts
|
||||
*CounterOpts
|
||||
labels []string
|
||||
registryVersion *semver.Version
|
||||
expectedMetricFamilyCount int
|
||||
@ -134,7 +134,7 @@ func TestCounterVec(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "Test non deprecated",
|
||||
CounterOpts: CounterOpts{
|
||||
CounterOpts: &CounterOpts{
|
||||
Namespace: "namespace",
|
||||
Name: "metric_test_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -147,7 +147,7 @@ func TestCounterVec(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "Test deprecated",
|
||||
CounterOpts: CounterOpts{
|
||||
CounterOpts: &CounterOpts{
|
||||
Namespace: "namespace",
|
||||
Name: "metric_test_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -161,7 +161,7 @@ func TestCounterVec(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "Test hidden",
|
||||
CounterOpts: CounterOpts{
|
||||
CounterOpts: &CounterOpts{
|
||||
Namespace: "namespace",
|
||||
Name: "metric_test_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -177,7 +177,7 @@ func TestCounterVec(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
registry := NewKubeRegistry(*test.registryVersion)
|
||||
registry := newKubeRegistry(*test.registryVersion)
|
||||
c := NewCounterVec(test.CounterOpts, test.labels)
|
||||
registry.MustRegister(c)
|
||||
c.WithLabelValues("1", "2").Inc()
|
||||
|
@ -29,7 +29,7 @@ This extends the prometheus.Collector interface to allow customization of the me
|
||||
registration process. Defer metric initialization until Create() is called, which then
|
||||
delegates to the underlying metric's initializeMetric or initializeDeprecatedMetric
|
||||
method call depending on whether the metric is deprecated or not.
|
||||
*/
|
||||
*/
|
||||
type KubeCollector interface {
|
||||
Collector
|
||||
LazyMetric
|
||||
@ -46,7 +46,7 @@ type KubeCollector interface {
|
||||
LazyMetric defines our registration functionality. LazyMetric objects are expected
|
||||
to lazily instantiate metrics (i.e defer metric instantiation until when
|
||||
the Create() function is explicitly called).
|
||||
*/
|
||||
*/
|
||||
type LazyMetric interface {
|
||||
Create(*semver.Version) bool
|
||||
IsCreated() bool
|
||||
@ -59,7 +59,7 @@ lazyMetric implements LazyMetric. A lazy metric is lazy because it waits until m
|
||||
registration time before instantiation. Add it as an anonymous field to a struct that
|
||||
implements KubeCollector to get deferred registration behavior. You must call lazyInit
|
||||
with the KubeCollector itself as an argument.
|
||||
*/
|
||||
*/
|
||||
type lazyMetric struct {
|
||||
isDeprecated bool
|
||||
isHidden bool
|
||||
@ -136,7 +136,7 @@ This code is directly lifted from the prometheus codebase. It's a convenience st
|
||||
allows you satisfy the Collector interface automatically if you already satisfy the Metric interface.
|
||||
|
||||
For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/collector.go#L98-L120
|
||||
*/
|
||||
*/
|
||||
type selfCollector struct {
|
||||
metric prometheus.Metric
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func (o *CounterOpts) annotateStabilityLevel() {
|
||||
|
||||
// convenience function to allow easy transformation to the prometheus
|
||||
// counterpart. This will do more once we have a proper label abstraction
|
||||
func (o CounterOpts) toPromCounterOpts() prometheus.CounterOpts {
|
||||
func (o *CounterOpts) toPromCounterOpts() prometheus.CounterOpts {
|
||||
return prometheus.CounterOpts{
|
||||
Namespace: o.Namespace,
|
||||
Subsystem: o.Subsystem,
|
||||
|
@ -20,12 +20,11 @@ import (
|
||||
"github.com/blang/semver"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
||||
var (
|
||||
// todo: load the version dynamically at application boot.
|
||||
DefaultGlobalRegistry = NewKubeRegistry(semver.MustParse("1.15.0"))
|
||||
)
|
||||
var DefaultGlobalRegistry = NewKubeRegistry()
|
||||
|
||||
type KubeRegistry struct {
|
||||
PromRegistry
|
||||
@ -69,9 +68,23 @@ func (kr *KubeRegistry) Gather() ([]*dto.MetricFamily, error) {
|
||||
return kr.PromRegistry.Gather()
|
||||
}
|
||||
|
||||
// NewRegistry creates a new vanilla Registry without any Collectors
|
||||
func NewKubeRegistry() *KubeRegistry {
|
||||
v, err := parseVersion(version.Get())
|
||||
if err != nil {
|
||||
klog.Fatalf("Can't initialize a registry without a valid version %v", err)
|
||||
}
|
||||
if v == nil {
|
||||
klog.Fatalf("No valid version %v", *v)
|
||||
}
|
||||
return &KubeRegistry{
|
||||
PromRegistry: prometheus.NewRegistry(),
|
||||
version: semver.MustParse(*v),
|
||||
}
|
||||
}
|
||||
|
||||
// newKubeRegistry creates a new vanilla Registry without any Collectors
|
||||
// pre-registered.
|
||||
func NewKubeRegistry(version semver.Version) *KubeRegistry {
|
||||
func newKubeRegistry(version semver.Version) *KubeRegistry {
|
||||
return &KubeRegistry{
|
||||
PromRegistry: prometheus.NewRegistry(),
|
||||
version: version,
|
||||
|
@ -27,7 +27,7 @@ var (
|
||||
v115 = semver.MustParse("1.15.0")
|
||||
v114 = semver.MustParse("1.14.0")
|
||||
alphaCounter = NewCounter(
|
||||
CounterOpts{
|
||||
&CounterOpts{
|
||||
Namespace: "some_namespace",
|
||||
Name: "test_counter_name",
|
||||
Subsystem: "subsystem",
|
||||
@ -36,7 +36,7 @@ var (
|
||||
},
|
||||
)
|
||||
alphaDeprecatedCounter = NewCounter(
|
||||
CounterOpts{
|
||||
&CounterOpts{
|
||||
Namespace: "some_namespace",
|
||||
Name: "test_alpha_dep_counter",
|
||||
Subsystem: "subsystem",
|
||||
@ -46,7 +46,7 @@ var (
|
||||
},
|
||||
)
|
||||
alphaHiddenCounter = NewCounter(
|
||||
CounterOpts{
|
||||
&CounterOpts{
|
||||
Namespace: "some_namespace",
|
||||
Name: "test_alpha_hidden_counter",
|
||||
Subsystem: "subsystem",
|
||||
@ -56,7 +56,7 @@ var (
|
||||
},
|
||||
)
|
||||
stableCounter = NewCounter(
|
||||
CounterOpts{
|
||||
&CounterOpts{
|
||||
Namespace: "some_namespace",
|
||||
Name: "test_some_other_counter",
|
||||
Subsystem: "subsystem",
|
||||
@ -116,7 +116,7 @@ func TestRegister(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
registry := NewKubeRegistry(*test.registryVersion)
|
||||
registry := newKubeRegistry(*test.registryVersion)
|
||||
for i, m := range test.metrics {
|
||||
err := registry.Register(m)
|
||||
if err != test.expectedErrors[i] && err.Error() != test.expectedErrors[i].Error() {
|
||||
@ -183,7 +183,7 @@ func TestMustRegister(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
registry := NewKubeRegistry(*test.registryVersion)
|
||||
registry := newKubeRegistry(*test.registryVersion)
|
||||
for i, m := range test.metrics {
|
||||
if test.expectedPanics[i] {
|
||||
assert.Panics(t,
|
||||
|
40
pkg/util/metrics/version_parser.go
Normal file
40
pkg/util/metrics/version_parser.go
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
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 metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
apimachineryversion "k8s.io/apimachinery/pkg/version"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
versionRegexpString = `^v(\d+\.\d+\.\d+)`
|
||||
)
|
||||
|
||||
var (
|
||||
versionRe = regexp.MustCompile(versionRegexpString)
|
||||
)
|
||||
|
||||
func parseVersion(ver apimachineryversion.Info) (*string, error) {
|
||||
matches := versionRe.FindAllStringSubmatch(ver.String(), -1)
|
||||
|
||||
if len(matches) != 1 {
|
||||
return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", ver.String(), versionRe.String())
|
||||
}
|
||||
return &matches[0][1], nil
|
||||
}
|
56
pkg/util/metrics/version_parser_test.go
Normal file
56
pkg/util/metrics/version_parser_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
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 metrics
|
||||
|
||||
import (
|
||||
apimachineryversion "k8s.io/apimachinery/pkg/version"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVersionParsing(t *testing.T) {
|
||||
var tests = []struct {
|
||||
desc string
|
||||
versionString string
|
||||
expectedVersion string
|
||||
}{
|
||||
{
|
||||
"v1.15.0-alpha-1.12345",
|
||||
"v1.15.0-alpha-1.12345",
|
||||
"1.15.0",
|
||||
},
|
||||
{
|
||||
"Parse out defaulted string",
|
||||
"v0.0.0-master",
|
||||
"0.0.0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
version := apimachineryversion.Info{
|
||||
GitVersion: test.versionString,
|
||||
}
|
||||
parsedV, err := parseVersion(version)
|
||||
if err != nil {
|
||||
t.Fatalf("Should be able to parse %v", version)
|
||||
}
|
||||
if test.expectedVersion != *parsedV {
|
||||
t.Errorf("Got %v, wanted %v", *parsedV, test.expectedVersion)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user