mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 22:17:14 +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",
|
"opts.go",
|
||||||
"registry.go",
|
"registry.go",
|
||||||
"util.go",
|
"util.go",
|
||||||
|
"version_parser.go",
|
||||||
"wrappers.go",
|
"wrappers.go",
|
||||||
],
|
],
|
||||||
importpath = "k8s.io/kubernetes/pkg/util/metrics",
|
importpath = "k8s.io/kubernetes/pkg/util/metrics",
|
||||||
deps = [
|
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",
|
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||||
"//vendor/github.com/blang/semver:go_default_library",
|
"//vendor/github.com/blang/semver:go_default_library",
|
||||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||||
@ -32,9 +35,11 @@ go_test(
|
|||||||
"counter_test.go",
|
"counter_test.go",
|
||||||
"registry_test.go",
|
"registry_test.go",
|
||||||
"util_test.go",
|
"util_test.go",
|
||||||
|
"version_parser_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/util/flowcontrol: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/blang/semver:go_default_library",
|
||||||
"//vendor/github.com/prometheus/client_golang/prometheus: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.
|
// NewCounter returns an object which satisfies the KubeCollector and KubeCounter interfaces.
|
||||||
// However, the object returned will not measure anything unless the collector is first
|
// However, the object returned will not measure anything unless the collector is first
|
||||||
// registered, since the metric is lazily instantiated.
|
// registered, since the metric is lazily instantiated.
|
||||||
func NewCounter(opts CounterOpts) *kubeCounter {
|
func NewCounter(opts *CounterOpts) *kubeCounter {
|
||||||
// todo: handle defaulting better
|
// todo: handle defaulting better
|
||||||
if opts.StabilityLevel == "" {
|
if opts.StabilityLevel == "" {
|
||||||
opts.StabilityLevel = ALPHA
|
opts.StabilityLevel = ALPHA
|
||||||
}
|
}
|
||||||
kc := &kubeCounter{
|
kc := &kubeCounter{
|
||||||
CounterOpts: &opts,
|
CounterOpts: opts,
|
||||||
lazyMetric: lazyMetric{},
|
lazyMetric: lazyMetric{},
|
||||||
}
|
}
|
||||||
kc.setPrometheusCounter(noop)
|
kc.setPrometheusCounter(noop)
|
||||||
@ -85,10 +85,10 @@ type kubeCounterVec struct {
|
|||||||
// NewCounterVec returns an object which satisfies the KubeCollector and KubeCounterVec interfaces.
|
// NewCounterVec returns an object which satisfies the KubeCollector and KubeCounterVec interfaces.
|
||||||
// However, the object returned will not measure anything unless the collector is first
|
// However, the object returned will not measure anything unless the collector is first
|
||||||
// registered, since the metric is lazily instantiated.
|
// registered, since the metric is lazily instantiated.
|
||||||
func NewCounterVec(opts CounterOpts, labels []string) *kubeCounterVec {
|
func NewCounterVec(opts *CounterOpts, labels []string) *kubeCounterVec {
|
||||||
cv := &kubeCounterVec{
|
cv := &kubeCounterVec{
|
||||||
CounterVec: noopCounterVec,
|
CounterVec: noopCounterVec,
|
||||||
CounterOpts: &opts,
|
CounterOpts: opts,
|
||||||
originalLabels: labels,
|
originalLabels: labels,
|
||||||
lazyMetric: lazyMetric{},
|
lazyMetric: lazyMetric{},
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,14 @@ func TestCounter(t *testing.T) {
|
|||||||
v114 := semver.MustParse("1.14.0")
|
v114 := semver.MustParse("1.14.0")
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
desc string
|
desc string
|
||||||
CounterOpts
|
*CounterOpts
|
||||||
registryVersion *semver.Version
|
registryVersion *semver.Version
|
||||||
expectedMetricCount int
|
expectedMetricCount int
|
||||||
expectedHelp string
|
expectedHelp string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Test non deprecated",
|
desc: "Test non deprecated",
|
||||||
CounterOpts: CounterOpts{
|
CounterOpts: &CounterOpts{
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Name: "metric_test_name",
|
Name: "metric_test_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -48,7 +48,7 @@ func TestCounter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Test deprecated",
|
desc: "Test deprecated",
|
||||||
CounterOpts: CounterOpts{
|
CounterOpts: &CounterOpts{
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Name: "metric_test_name",
|
Name: "metric_test_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -62,7 +62,7 @@ func TestCounter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Test hidden",
|
desc: "Test hidden",
|
||||||
CounterOpts: CounterOpts{
|
CounterOpts: &CounterOpts{
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Name: "metric_test_name",
|
Name: "metric_test_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -77,7 +77,7 @@ func TestCounter(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
registry := NewKubeRegistry(*test.registryVersion)
|
registry := newKubeRegistry(*test.registryVersion)
|
||||||
c := NewCounter(test.CounterOpts)
|
c := NewCounter(test.CounterOpts)
|
||||||
registry.MustRegister(c)
|
registry.MustRegister(c)
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ func TestCounterVec(t *testing.T) {
|
|||||||
v114 := semver.MustParse("1.14.0")
|
v114 := semver.MustParse("1.14.0")
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
desc string
|
desc string
|
||||||
CounterOpts
|
*CounterOpts
|
||||||
labels []string
|
labels []string
|
||||||
registryVersion *semver.Version
|
registryVersion *semver.Version
|
||||||
expectedMetricFamilyCount int
|
expectedMetricFamilyCount int
|
||||||
@ -134,7 +134,7 @@ func TestCounterVec(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Test non deprecated",
|
desc: "Test non deprecated",
|
||||||
CounterOpts: CounterOpts{
|
CounterOpts: &CounterOpts{
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Name: "metric_test_name",
|
Name: "metric_test_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -147,7 +147,7 @@ func TestCounterVec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Test deprecated",
|
desc: "Test deprecated",
|
||||||
CounterOpts: CounterOpts{
|
CounterOpts: &CounterOpts{
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Name: "metric_test_name",
|
Name: "metric_test_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -161,7 +161,7 @@ func TestCounterVec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Test hidden",
|
desc: "Test hidden",
|
||||||
CounterOpts: CounterOpts{
|
CounterOpts: &CounterOpts{
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
Name: "metric_test_name",
|
Name: "metric_test_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -177,7 +177,7 @@ func TestCounterVec(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
registry := NewKubeRegistry(*test.registryVersion)
|
registry := newKubeRegistry(*test.registryVersion)
|
||||||
c := NewCounterVec(test.CounterOpts, test.labels)
|
c := NewCounterVec(test.CounterOpts, test.labels)
|
||||||
registry.MustRegister(c)
|
registry.MustRegister(c)
|
||||||
c.WithLabelValues("1", "2").Inc()
|
c.WithLabelValues("1", "2").Inc()
|
||||||
|
@ -67,7 +67,7 @@ func (o *CounterOpts) annotateStabilityLevel() {
|
|||||||
|
|
||||||
// convenience function to allow easy transformation to the prometheus
|
// convenience function to allow easy transformation to the prometheus
|
||||||
// counterpart. This will do more once we have a proper label abstraction
|
// 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{
|
return prometheus.CounterOpts{
|
||||||
Namespace: o.Namespace,
|
Namespace: o.Namespace,
|
||||||
Subsystem: o.Subsystem,
|
Subsystem: o.Subsystem,
|
||||||
|
@ -20,12 +20,11 @@ import (
|
|||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
"k8s.io/klog"
|
||||||
|
"k8s.io/kubernetes/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var DefaultGlobalRegistry = NewKubeRegistry()
|
||||||
// todo: load the version dynamically at application boot.
|
|
||||||
DefaultGlobalRegistry = NewKubeRegistry(semver.MustParse("1.15.0"))
|
|
||||||
)
|
|
||||||
|
|
||||||
type KubeRegistry struct {
|
type KubeRegistry struct {
|
||||||
PromRegistry
|
PromRegistry
|
||||||
@ -69,9 +68,23 @@ func (kr *KubeRegistry) Gather() ([]*dto.MetricFamily, error) {
|
|||||||
return kr.PromRegistry.Gather()
|
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.
|
// pre-registered.
|
||||||
func NewKubeRegistry(version semver.Version) *KubeRegistry {
|
func newKubeRegistry(version semver.Version) *KubeRegistry {
|
||||||
return &KubeRegistry{
|
return &KubeRegistry{
|
||||||
PromRegistry: prometheus.NewRegistry(),
|
PromRegistry: prometheus.NewRegistry(),
|
||||||
version: version,
|
version: version,
|
||||||
|
@ -27,7 +27,7 @@ var (
|
|||||||
v115 = semver.MustParse("1.15.0")
|
v115 = semver.MustParse("1.15.0")
|
||||||
v114 = semver.MustParse("1.14.0")
|
v114 = semver.MustParse("1.14.0")
|
||||||
alphaCounter = NewCounter(
|
alphaCounter = NewCounter(
|
||||||
CounterOpts{
|
&CounterOpts{
|
||||||
Namespace: "some_namespace",
|
Namespace: "some_namespace",
|
||||||
Name: "test_counter_name",
|
Name: "test_counter_name",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -36,7 +36,7 @@ var (
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
alphaDeprecatedCounter = NewCounter(
|
alphaDeprecatedCounter = NewCounter(
|
||||||
CounterOpts{
|
&CounterOpts{
|
||||||
Namespace: "some_namespace",
|
Namespace: "some_namespace",
|
||||||
Name: "test_alpha_dep_counter",
|
Name: "test_alpha_dep_counter",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -46,7 +46,7 @@ var (
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
alphaHiddenCounter = NewCounter(
|
alphaHiddenCounter = NewCounter(
|
||||||
CounterOpts{
|
&CounterOpts{
|
||||||
Namespace: "some_namespace",
|
Namespace: "some_namespace",
|
||||||
Name: "test_alpha_hidden_counter",
|
Name: "test_alpha_hidden_counter",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -56,7 +56,7 @@ var (
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
stableCounter = NewCounter(
|
stableCounter = NewCounter(
|
||||||
CounterOpts{
|
&CounterOpts{
|
||||||
Namespace: "some_namespace",
|
Namespace: "some_namespace",
|
||||||
Name: "test_some_other_counter",
|
Name: "test_some_other_counter",
|
||||||
Subsystem: "subsystem",
|
Subsystem: "subsystem",
|
||||||
@ -116,7 +116,7 @@ func TestRegister(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
registry := NewKubeRegistry(*test.registryVersion)
|
registry := newKubeRegistry(*test.registryVersion)
|
||||||
for i, m := range test.metrics {
|
for i, m := range test.metrics {
|
||||||
err := registry.Register(m)
|
err := registry.Register(m)
|
||||||
if err != test.expectedErrors[i] && err.Error() != test.expectedErrors[i].Error() {
|
if err != test.expectedErrors[i] && err.Error() != test.expectedErrors[i].Error() {
|
||||||
@ -183,7 +183,7 @@ func TestMustRegister(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
registry := NewKubeRegistry(*test.registryVersion)
|
registry := newKubeRegistry(*test.registryVersion)
|
||||||
for i, m := range test.metrics {
|
for i, m := range test.metrics {
|
||||||
if test.expectedPanics[i] {
|
if test.expectedPanics[i] {
|
||||||
assert.Panics(t,
|
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