github.com/netdata/go.d.plugin@v0.58.1/agent/discovery/sd/pipeline/classify.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package pipeline
     4  
     5  import (
     6  	"bytes"
     7  	"strings"
     8  	"text/template"
     9  
    10  	"github.com/netdata/go.d.plugin/agent/discovery/sd/model"
    11  	"github.com/netdata/go.d.plugin/logger"
    12  )
    13  
    14  func newTargetClassificator(cfg []ClassifyRuleConfig) (*targetClassificator, error) {
    15  	rules, err := newClassifyRules(cfg)
    16  	if err != nil {
    17  		return nil, err
    18  	}
    19  
    20  	c := &targetClassificator{
    21  		rules: rules,
    22  		buf:   bytes.Buffer{},
    23  	}
    24  
    25  	return c, nil
    26  }
    27  
    28  type (
    29  	targetClassificator struct {
    30  		*logger.Logger
    31  		rules []*classifyRule
    32  		buf   bytes.Buffer
    33  	}
    34  
    35  	classifyRule struct {
    36  		name  string
    37  		sr    selector
    38  		tags  model.Tags
    39  		match []*classifyRuleMatch
    40  	}
    41  	classifyRuleMatch struct {
    42  		tags model.Tags
    43  		expr *template.Template
    44  	}
    45  )
    46  
    47  func (c *targetClassificator) classify(tgt model.Target) model.Tags {
    48  	var tags model.Tags
    49  
    50  	for i, rule := range c.rules {
    51  		if !rule.sr.matches(tgt.Tags()) {
    52  			continue
    53  		}
    54  
    55  		for j, match := range rule.match {
    56  			c.buf.Reset()
    57  
    58  			if err := match.expr.Execute(&c.buf, tgt); err != nil {
    59  				c.Warningf("failed to execute classify rule[%d]->match[%d]->expr on target '%s'", i+1, j+1, tgt.TUID())
    60  				continue
    61  			}
    62  			if strings.TrimSpace(c.buf.String()) != "true" {
    63  				continue
    64  			}
    65  
    66  			if tags == nil {
    67  				tags = model.NewTags()
    68  			}
    69  
    70  			tags.Merge(rule.tags)
    71  			tags.Merge(match.tags)
    72  		}
    73  	}
    74  
    75  	return tags
    76  }
    77  
    78  func newClassifyRules(cfg []ClassifyRuleConfig) ([]*classifyRule, error) {
    79  	var rules []*classifyRule
    80  
    81  	fmap := newFuncMap()
    82  
    83  	for _, ruleCfg := range cfg {
    84  		rule := classifyRule{name: ruleCfg.Name}
    85  
    86  		sr, err := parseSelector(ruleCfg.Selector)
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  		rule.sr = sr
    91  
    92  		tags, err := model.ParseTags(ruleCfg.Tags)
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  		rule.tags = tags
    97  
    98  		for _, matchCfg := range ruleCfg.Match {
    99  			var match classifyRuleMatch
   100  
   101  			tags, err := model.ParseTags(matchCfg.Tags)
   102  			if err != nil {
   103  				return nil, err
   104  			}
   105  			match.tags = tags
   106  
   107  			tmpl, err := parseTemplate(matchCfg.Expr, fmap)
   108  			if err != nil {
   109  				return nil, err
   110  			}
   111  			match.expr = tmpl
   112  
   113  			rule.match = append(rule.match, &match)
   114  		}
   115  
   116  		rules = append(rules, &rule)
   117  	}
   118  
   119  	return rules, nil
   120  }
   121  
   122  func parseTemplate(s string, fmap template.FuncMap) (*template.Template, error) {
   123  	return template.New("root").
   124  		Option("missingkey=error").
   125  		Funcs(fmap).
   126  		Parse(s)
   127  }