prefix GVK labels in CustomResourceMonitoring
This will prefix the auto-generated GVK labels for CustomResources with customresource_ to make it a bit more clear that these labels got generated. Signed-off-by: Mario Constanti <mario@constanti.de>
This commit is contained in:
parent
f1288f943a
commit
7130bd0d2b
|
|
@ -49,7 +49,7 @@ spec:
|
||||||
- --resources=certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,foos,horizontalpodautoscalers,ingresses,jobs,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,secrets,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments,verticalpodautoscalers
|
- --resources=certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,foos,horizontalpodautoscalers,ingresses,jobs,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,secrets,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments,verticalpodautoscalers
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: The `group`, `version`, and `kind` common labels are reserved, and will be overwritten by the values from the `groupVersionKind` field.
|
NOTE: The `customresource_group`, `customresource_version`, and `customresource_kind` common labels are reserved, and will be overwritten by the values from the `groupVersionKind` field.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@ import (
|
||||||
"k8s.io/kube-state-metrics/v2/pkg/customresource"
|
"k8s.io/kube-state-metrics/v2/pkg/customresource"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// customResourceState is used to prefix the auto-generated GVK labels as well as an appendix for the metric itself
|
||||||
|
// if no custom metric name is defined
|
||||||
|
const customResourceState string = "customresource"
|
||||||
|
|
||||||
// Metrics is the top level configuration object.
|
// Metrics is the top level configuration object.
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
Spec MetricsSpec `yaml:"spec" json:"spec"`
|
Spec MetricsSpec `yaml:"spec" json:"spec"`
|
||||||
|
|
@ -64,7 +68,7 @@ type Resource struct {
|
||||||
func (r Resource) GetMetricNamePrefix() string {
|
func (r Resource) GetMetricNamePrefix() string {
|
||||||
p := r.MetricNamePrefix
|
p := r.MetricNamePrefix
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return "kube_crd"
|
return "kube_" + customResourceState
|
||||||
}
|
}
|
||||||
return *p
|
return *p
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,25 @@ limitations under the License.
|
||||||
package customresourcestate
|
package customresourcestate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewCustomResourceMetrics(t *testing.T) {
|
func TestNewCustomResourceMetrics(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
r Resource
|
r Resource
|
||||||
wantErr bool
|
wantErr bool
|
||||||
name string
|
wantResult *customResourceMetrics
|
||||||
|
name string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// https://github.com/kubernetes/kube-state-metrics/issues/1886
|
// https://github.com/kubernetes/kube-state-metrics/issues/1886
|
||||||
name: "dynamic metric type (not just hardcoded to gauge)",
|
name: "cr metric with dynamic metric type",
|
||||||
r: Resource{
|
r: Resource{
|
||||||
GroupVersionKind: GroupVersionKind{
|
GroupVersionKind: GroupVersionKind{
|
||||||
Group: "apps",
|
Group: "apps",
|
||||||
|
|
@ -39,6 +46,9 @@ func TestNewCustomResourceMetrics(t *testing.T) {
|
||||||
LabelsFromPath: map[string][]string{
|
LabelsFromPath: map[string][]string{
|
||||||
"name": {"metadata", "name"},
|
"name": {"metadata", "name"},
|
||||||
},
|
},
|
||||||
|
CommonLabels: map[string]string{
|
||||||
|
"hello": "world",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Metrics: []Generator{
|
Metrics: []Generator{
|
||||||
{
|
{
|
||||||
|
|
@ -60,16 +70,178 @@ func TestNewCustomResourceMetrics(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
|
wantResult: &customResourceMetrics{
|
||||||
|
MetricNamePrefix: "kube_customresource",
|
||||||
|
GroupVersionKind: schema.GroupVersionKind{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
ResourceName: "deployments",
|
||||||
|
Families: []compiledFamily{
|
||||||
|
{
|
||||||
|
Name: "kube_customresource_test_metrics",
|
||||||
|
Help: "metrics for testing",
|
||||||
|
Each: &compiledInfo{},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"customresource_group": "apps",
|
||||||
|
"customresource_kind": "Deployment",
|
||||||
|
"customresource_version": "v1",
|
||||||
|
"hello": "world",
|
||||||
|
},
|
||||||
|
LabelFromPath: map[string]valuePath{
|
||||||
|
"name": mustCompilePath(t, "metadata", "name"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cr metric with custom prefix",
|
||||||
|
r: Resource{
|
||||||
|
GroupVersionKind: GroupVersionKind{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
Labels: Labels{
|
||||||
|
LabelsFromPath: map[string][]string{
|
||||||
|
"name": {"metadata", "name"},
|
||||||
|
},
|
||||||
|
CommonLabels: map[string]string{
|
||||||
|
"hello": "world",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metrics: []Generator{
|
||||||
|
{
|
||||||
|
Name: "test_metrics",
|
||||||
|
Help: "metrics for testing",
|
||||||
|
Each: Metric{
|
||||||
|
Type: MetricTypeInfo,
|
||||||
|
Info: &MetricInfo{
|
||||||
|
MetricMeta: MetricMeta{
|
||||||
|
Path: []string{
|
||||||
|
"metadata",
|
||||||
|
"annotations",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LabelFromKey: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MetricNamePrefix: pointer.String("apps_deployment"),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
wantResult: &customResourceMetrics{
|
||||||
|
MetricNamePrefix: "apps_deployment",
|
||||||
|
GroupVersionKind: schema.GroupVersionKind{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
ResourceName: "deployments",
|
||||||
|
Families: []compiledFamily{
|
||||||
|
{
|
||||||
|
Name: "apps_deployment_test_metrics",
|
||||||
|
Help: "metrics for testing",
|
||||||
|
Each: &compiledInfo{},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"customresource_group": "apps",
|
||||||
|
"customresource_kind": "Deployment",
|
||||||
|
"customresource_version": "v1",
|
||||||
|
"hello": "world",
|
||||||
|
},
|
||||||
|
LabelFromPath: map[string]valuePath{
|
||||||
|
"name": mustCompilePath(t, "metadata", "name"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cr metric with custom prefix - expect error",
|
||||||
|
r: Resource{
|
||||||
|
GroupVersionKind: GroupVersionKind{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
Labels: Labels{
|
||||||
|
LabelsFromPath: map[string][]string{
|
||||||
|
"name": {"metadata", "name"},
|
||||||
|
},
|
||||||
|
CommonLabels: map[string]string{
|
||||||
|
"hello": "world",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metrics: []Generator{
|
||||||
|
{
|
||||||
|
Name: "test_metrics",
|
||||||
|
Help: "metrics for testing",
|
||||||
|
Each: Metric{
|
||||||
|
Type: MetricTypeInfo,
|
||||||
|
Info: &MetricInfo{
|
||||||
|
MetricMeta: MetricMeta{
|
||||||
|
Path: []string{
|
||||||
|
"metadata",
|
||||||
|
"annotations",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LabelFromKey: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MetricNamePrefix: pointer.String("apps_deployment"),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
wantResult: &customResourceMetrics{
|
||||||
|
GroupVersionKind: schema.GroupVersionKind{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
ResourceName: "deployments",
|
||||||
|
Families: []compiledFamily{
|
||||||
|
{
|
||||||
|
Name: "apps_deployment_test_metrics",
|
||||||
|
Help: "metrics for testing",
|
||||||
|
Each: &compiledInfo{},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"customresource_group": "apps",
|
||||||
|
"customresource_kind": "Deployment",
|
||||||
|
"customresource_version": "v1",
|
||||||
|
"hello": "world",
|
||||||
|
},
|
||||||
|
LabelFromPath: map[string]valuePath{
|
||||||
|
"name": mustCompilePath(t, "metadata", "name"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
v, err := NewCustomResourceMetrics(tt.r)
|
v, err := NewCustomResourceMetrics(tt.r)
|
||||||
expectedError := v.(*customResourceMetrics).Families[0].Each.Type() != "info"
|
if err != nil {
|
||||||
if (err != nil) != tt.wantErr || expectedError {
|
t.Errorf(err.Error())
|
||||||
t.Errorf("NewCustomResourceMetrics() error = %v, wantErr %v", err, tt.wantErr)
|
}
|
||||||
return
|
|
||||||
|
// convert to JSON for easier nil comparison
|
||||||
|
ttWantJSON, _ := json.Marshal(tt.wantResult)
|
||||||
|
customResourceMetricJSON, _ := json.Marshal(v.(*customResourceMetrics))
|
||||||
|
|
||||||
|
if !tt.wantErr && !reflect.DeepEqual(ttWantJSON, customResourceMetricJSON) {
|
||||||
|
t.Errorf("NewCustomResourceMetrics: error expected %v", tt.wantErr)
|
||||||
|
t.Errorf("NewCustomResourceMetrics:\n %#v\n is not deep equal\n %#v", v, tt.wantResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.wantErr && reflect.DeepEqual(ttWantJSON, customResourceMetricJSON) {
|
||||||
|
t.Errorf("NewCustomResourceMetrics: error expected %v", tt.wantErr)
|
||||||
|
t.Errorf("NewCustomResourceMetrics:\n %#v\n is not deep equal\n %#v", v, tt.wantResult)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ func compile(resource Resource) ([]compiledFamily, error) {
|
||||||
if resource.CommonLabels == nil {
|
if resource.CommonLabels == nil {
|
||||||
resource.CommonLabels = map[string]string{}
|
resource.CommonLabels = map[string]string{}
|
||||||
}
|
}
|
||||||
resource.CommonLabels["group"] = resource.GroupVersionKind.Group
|
resource.CommonLabels[customResourceState+"_group"] = resource.GroupVersionKind.Group
|
||||||
resource.CommonLabels["version"] = resource.GroupVersionKind.Version
|
resource.CommonLabels[customResourceState+"_version"] = resource.GroupVersionKind.Version
|
||||||
resource.CommonLabels["kind"] = resource.GroupVersionKind.Kind
|
resource.CommonLabels[customResourceState+"_kind"] = resource.GroupVersionKind.Kind
|
||||||
for _, f := range resource.Metrics {
|
for _, f := range resource.Metrics {
|
||||||
family, err := compileFamily(f, resource)
|
family, err := compileFamily(f, resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,7 @@ func Test_fullName(t *testing.T) {
|
||||||
resource: r(nil),
|
resource: r(nil),
|
||||||
f: count,
|
f: count,
|
||||||
},
|
},
|
||||||
want: "kube_crd_count",
|
want: "kube_customresource_count",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no prefix",
|
name: "no prefix",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue