1 // Copyright 2019 The Operator-SDK Authors
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
21 "github.com/pkg/errors"
22 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23 "k8s.io/apimachinery/pkg/runtime/schema"
24 "k8s.io/client-go/rest"
25 kcollector "k8s.io/kube-state-metrics/pkg/collector"
26 ksmetric "k8s.io/kube-state-metrics/pkg/metric"
27 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
30 var log = logf.Log.WithName("kubemetrics")
32 // GenerateAndServeCRMetrics generates CustomResource specific metrics for each custom resource GVK in operatorGVKs.
33 // A list of namespaces, ns, can be passed to ServeCRMetrics to scope the generated metrics. Passing nil or
34 // an empty list of namespaces will result in an error.
35 // The function also starts serving the generated collections of the metrics on given host and port.
36 func GenerateAndServeCRMetrics(cfg *rest.Config,
38 operatorGVKs []schema.GroupVersionKind,
39 host string, port int32) error {
40 // We have to have at least one namespace.
42 return errors.New("namespaces were empty; pass at least one namespace to generate custom resource metrics")
44 // Create new unstructured client.
45 var collectors [][]kcollector.Collector
46 log.V(1).Info("Starting collecting operator types")
47 // Loop through all the possible operator/custom resource specific types.
48 for _, gvk := range operatorGVKs {
49 apiVersion := gvk.GroupVersion().String()
51 // Generate metric based on the kind.
52 metricFamilies := generateMetricFamilies(gvk.Kind)
53 log.V(1).Info("Generating metric families", "apiVersion", apiVersion, "kind", kind)
54 dclient, err := newClientForGVK(cfg, apiVersion, kind)
58 // Generate collector based on the group/version, kind and the metric families.
59 c := NewCollectors(dclient, ns, apiVersion, kind, metricFamilies)
60 collectors = append(collectors, c)
62 // Start serving metrics.
63 log.V(1).Info("Starting serving custom resource metrics")
64 go ServeMetrics(collectors, host, port)
69 func generateMetricFamilies(kind string) []ksmetric.FamilyGenerator {
70 helpText := fmt.Sprintf("Information about the %s custom resource.", kind)
71 kindName := strings.ToLower(kind)
72 metricName := fmt.Sprintf("%s_info", kindName)
74 return []ksmetric.FamilyGenerator{
75 ksmetric.FamilyGenerator{
79 GenerateFunc: func(obj interface{}) *ksmetric.Family {
80 crd := obj.(*unstructured.Unstructured)
81 return &ksmetric.Family{
82 Metrics: []*ksmetric.Metric{
85 LabelKeys: []string{"namespace", kindName},
86 LabelValues: []string{crd.GetNamespace(), crd.GetName()},