github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/sinks/hawkular/driver.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     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
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     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.
    14  
    15  package hawkular
    16  
    17  import (
    18  	"crypto/tls"
    19  	"crypto/x509"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"net/url"
    24  	"strconv"
    25  	"sync"
    26  
    27  	"github.com/golang/glog"
    28  	"github.com/hawkular/hawkular-client-go/metrics"
    29  
    30  	kube_client "k8s.io/client-go/rest"
    31  	kubeClientCmd "k8s.io/client-go/tools/clientcmd"
    32  	"k8s.io/heapster/metrics/core"
    33  )
    34  
    35  const (
    36  	unitsTag           = "units"
    37  	descriptionTag     = "_description"
    38  	descriptorTag      = "descriptor_name"
    39  	groupTag           = "group_id"
    40  	separator          = "/"
    41  	batchSizeDefault   = 1000
    42  	concurrencyDefault = 5
    43  
    44  	nodeId string = "labelNodeId"
    45  
    46  	labelTagPrefixOpts    = "labelTagPrefix"
    47  	labelTagPrefixDefault = "labels."
    48  
    49  	defaultServiceAccountFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
    50  )
    51  
    52  // START: ExternalSink interface implementations
    53  
    54  func (h *hawkularSink) Register(mds []core.MetricDescriptor) error {
    55  	// Create model definitions based on the MetricDescriptors
    56  	for _, md := range mds {
    57  		hmd := h.descriptorToDefinition(&md)
    58  		h.models[md.Name] = &hmd
    59  	}
    60  
    61  	if !h.disablePreCaching {
    62  		// Fetch currently known metrics from Hawkular-Metrics and cache them
    63  		err := h.cacheDefinitions()
    64  		if err != nil {
    65  			return err
    66  		}
    67  	}
    68  
    69  	return nil
    70  }
    71  
    72  func (h *hawkularSink) Stop() {
    73  	h.regLock.Lock()
    74  	defer h.regLock.Unlock()
    75  	h.init()
    76  }
    77  
    78  func (h *hawkularSink) ExportData(db *core.DataBatch) {
    79  	totalCount := 0
    80  	h.runId++
    81  	for _, ms := range db.MetricSets {
    82  		totalCount += len(ms.MetricValues)
    83  		totalCount += len(ms.LabeledMetrics)
    84  	}
    85  
    86  	if len(db.MetricSets) > 0 {
    87  		tmhs := make(map[string][]metrics.MetricHeader)
    88  
    89  		if len(h.labelTenant) == 0 {
    90  			tmhs[h.client.Tenant] = make([]metrics.MetricHeader, 0, totalCount)
    91  		}
    92  
    93  		wg := &sync.WaitGroup{}
    94  
    95  		for _, ms := range db.MetricSets {
    96  
    97  			// Transform ms.MetricValues to LabeledMetrics first
    98  			mvlms := metricValueToLabeledMetric(ms.MetricValues)
    99  			lms := make([]core.LabeledMetric, 0, len(mvlms)+len(ms.LabeledMetrics))
   100  
   101  			lms = append(lms, mvlms...)
   102  			lms = append(lms, ms.LabeledMetrics...)
   103  
   104  		Store:
   105  			for _, labeledMetric := range lms {
   106  
   107  				for _, filter := range h.filters {
   108  					if !filter(ms, labeledMetric.Name) {
   109  						continue Store
   110  					}
   111  				}
   112  
   113  				tenant := h.client.Tenant
   114  
   115  				if len(h.labelTenant) > 0 {
   116  					if v, found := ms.Labels[h.labelTenant]; found {
   117  						tenant = v
   118  					}
   119  				}
   120  
   121  				h.registerLabeledIfNecessaryInline(ms, labeledMetric, wg, metrics.Tenant(tenant))
   122  				mH, err := h.pointToLabeledMetricHeader(ms, labeledMetric, db.Timestamp)
   123  				if err != nil {
   124  					// One transformation error should not prevent the whole process
   125  					glog.Errorf(err.Error())
   126  					continue
   127  				}
   128  
   129  				if _, found := tmhs[tenant]; !found {
   130  					tmhs[tenant] = make([]metrics.MetricHeader, 0)
   131  				}
   132  
   133  				tmhs[tenant] = append(tmhs[tenant], *mH)
   134  			}
   135  		}
   136  		h.sendData(tmhs, wg) // Send to a limited channel? Only batches.. egg.
   137  		wg.Wait()
   138  		// glog.V(4).Infof("ExportData updated %d tags, total size of cached tags is %d\n", updatedTags, len(h.reg))
   139  	}
   140  	h.expireCache(h.runId)
   141  }
   142  
   143  func metricValueToLabeledMetric(msValues map[string]core.MetricValue) []core.LabeledMetric {
   144  	lms := make([]core.LabeledMetric, 0, len(msValues))
   145  	for metricName, metricValue := range msValues {
   146  		lm := core.LabeledMetric{
   147  			Name:        metricName,
   148  			MetricValue: metricValue,
   149  			Labels:      make(map[string]string, 0),
   150  		}
   151  		lms = append(lms, lm)
   152  	}
   153  	return lms
   154  }
   155  
   156  func (h *hawkularSink) DebugInfo() string {
   157  	info := fmt.Sprintf("%s\n", h.Name())
   158  
   159  	h.regLock.Lock()
   160  	defer h.regLock.Unlock()
   161  	info += fmt.Sprintf("Cached metrics: %d\n", len(h.expReg))
   162  	if len(h.labelTenant) > 0 {
   163  		info += fmt.Sprintf("Using label '%s' as tenant information\n", h.labelTenant)
   164  	}
   165  	if len(h.labelNodeId) > 0 {
   166  		info += fmt.Sprintf("Using label '%s' as node identified in resourceid\n", h.labelNodeId)
   167  	}
   168  
   169  	// TODO Add here statistics from the Hawkular-Metrics client instance
   170  	return info
   171  }
   172  
   173  func (h *hawkularSink) Name() string {
   174  	return "Hawkular-Metrics Sink"
   175  }
   176  
   177  // NewHawkularSink Creates and returns a new hawkularSink instance
   178  func NewHawkularSink(u *url.URL) (core.DataSink, error) {
   179  	sink := &hawkularSink{
   180  		uri:       u,
   181  		batchSize: 1000,
   182  	}
   183  	if err := sink.init(); err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	metrics := make([]core.MetricDescriptor, 0, len(core.AllMetrics))
   188  	for _, metric := range core.AllMetrics {
   189  		metrics = append(metrics, metric.MetricDescriptor)
   190  	}
   191  	sink.Register(metrics)
   192  	return sink, nil
   193  }
   194  
   195  func (h *hawkularSink) init() error {
   196  	h.models = make(map[string]*metrics.MetricDefinition)
   197  	h.modifiers = make([]metrics.Modifier, 0)
   198  	h.filters = make([]Filter, 0)
   199  	h.batchSize = batchSizeDefault
   200  	h.expReg = make(map[string]*expiringItem)
   201  	h.cacheAge = 2
   202  	h.runId = 0
   203  
   204  	p := metrics.Parameters{
   205  		Tenant:      "heapster",
   206  		Url:         h.uri.String(),
   207  		Concurrency: concurrencyDefault,
   208  	}
   209  
   210  	opts := h.uri.Query()
   211  
   212  	if v, found := opts["tenant"]; found {
   213  		p.Tenant = v[0]
   214  	}
   215  
   216  	if v, found := opts["labelToTenant"]; found {
   217  		h.labelTenant = v[0]
   218  	}
   219  
   220  	if v, found := opts[labelTagPrefixOpts]; found {
   221  		h.labelTagPrefix = v[0]
   222  	} else {
   223  		h.labelTagPrefix = labelTagPrefixDefault
   224  	}
   225  
   226  	if v, found := opts[nodeId]; found {
   227  		h.labelNodeId = v[0]
   228  	}
   229  
   230  	if v, found := opts["useServiceAccount"]; found {
   231  		if b, _ := strconv.ParseBool(v[0]); b {
   232  			// If a readable service account token exists, then use it
   233  			if contents, err := ioutil.ReadFile(defaultServiceAccountFile); err == nil {
   234  				p.Token = string(contents)
   235  			}
   236  		}
   237  	}
   238  
   239  	// Authentication / Authorization parameters
   240  	tC := &tls.Config{}
   241  
   242  	if v, found := opts["auth"]; found {
   243  		if _, f := opts["caCert"]; f {
   244  			return fmt.Errorf("Both auth and caCert files provided, combination is not supported")
   245  		}
   246  		if len(v[0]) > 0 {
   247  			// Authfile
   248  			kubeConfig, err := kubeClientCmd.NewNonInteractiveDeferredLoadingClientConfig(&kubeClientCmd.ClientConfigLoadingRules{
   249  				ExplicitPath: v[0]},
   250  				&kubeClientCmd.ConfigOverrides{}).ClientConfig()
   251  			if err != nil {
   252  				return err
   253  			}
   254  			tC, err = kube_client.TLSConfigFor(kubeConfig)
   255  			if err != nil {
   256  				return err
   257  			}
   258  		}
   259  	}
   260  
   261  	if u, found := opts["user"]; found {
   262  		if _, wrong := opts["useServiceAccount"]; wrong {
   263  			return fmt.Errorf("If user and password are used, serviceAccount cannot be used")
   264  		}
   265  		if p, f := opts["pass"]; f {
   266  			h.modifiers = append(h.modifiers, func(req *http.Request) error {
   267  				req.SetBasicAuth(u[0], p[0])
   268  				return nil
   269  			})
   270  		}
   271  	}
   272  
   273  	if v, found := opts["caCert"]; found {
   274  		caCert, err := ioutil.ReadFile(v[0])
   275  		if err != nil {
   276  			return err
   277  		}
   278  
   279  		caCertPool := x509.NewCertPool()
   280  		caCertPool.AppendCertsFromPEM(caCert)
   281  
   282  		tC.RootCAs = caCertPool
   283  	}
   284  
   285  	if v, found := opts["insecure"]; found {
   286  		_, f := opts["caCert"]
   287  		_, f2 := opts["auth"]
   288  		if f || f2 {
   289  			return fmt.Errorf("Insecure can't be defined with auth or caCert")
   290  		}
   291  		insecure, err := strconv.ParseBool(v[0])
   292  		if err != nil {
   293  			return err
   294  		}
   295  		tC.InsecureSkipVerify = insecure
   296  	}
   297  
   298  	p.TLSConfig = tC
   299  
   300  	// Filters
   301  	if v, found := opts["filter"]; found {
   302  		filters, err := parseFilters(v)
   303  		if err != nil {
   304  			return err
   305  		}
   306  		h.filters = filters
   307  	}
   308  
   309  	// Concurrency limitations
   310  	if v, found := opts["concurrencyLimit"]; found {
   311  		cs, err := strconv.Atoi(v[0])
   312  		if err != nil || cs < 0 {
   313  			return fmt.Errorf("Supplied concurrency value of %s is invalid", v[0])
   314  		}
   315  		p.Concurrency = cs
   316  	}
   317  
   318  	if v, found := opts["batchSize"]; found {
   319  		bs, err := strconv.Atoi(v[0])
   320  		if err != nil || bs < 0 {
   321  			return fmt.Errorf("Supplied batchSize value of %s is invalid", v[0])
   322  		}
   323  		h.batchSize = bs
   324  	}
   325  
   326  	if v, found := opts["disablePreCache"]; found {
   327  		dpc, err := strconv.ParseBool(v[0])
   328  		if err != nil {
   329  			return fmt.Errorf("disablePreCache parameter value %s is invalid", v[0])
   330  		}
   331  		h.disablePreCaching = dpc
   332  	}
   333  
   334  	c, err := metrics.NewHawkularClient(p)
   335  	if err != nil {
   336  		return err
   337  	}
   338  
   339  	h.client = c
   340  
   341  	glog.Infof("Initialised Hawkular Sink with parameters %v", p)
   342  	return nil
   343  }