github.com/netdata/go.d.plugin@v0.58.1/modules/vsphere/match/match.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package match
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  
     9  	rs "github.com/netdata/go.d.plugin/modules/vsphere/resources"
    10  	"github.com/netdata/go.d.plugin/pkg/matcher"
    11  )
    12  
    13  type HostMatcher interface {
    14  	Match(*rs.Host) bool
    15  }
    16  
    17  type VMMatcher interface {
    18  	Match(*rs.VM) bool
    19  }
    20  
    21  type (
    22  	hostDCMatcher      struct{ m matcher.Matcher }
    23  	hostClusterMatcher struct{ m matcher.Matcher }
    24  	hostHostMatcher    struct{ m matcher.Matcher }
    25  	vmDCMatcher        struct{ m matcher.Matcher }
    26  	vmClusterMatcher   struct{ m matcher.Matcher }
    27  	vmHostMatcher      struct{ m matcher.Matcher }
    28  	vmVMMatcher        struct{ m matcher.Matcher }
    29  	orHostMatcher      struct{ lhs, rhs HostMatcher }
    30  	orVMMatcher        struct{ lhs, rhs VMMatcher }
    31  	andHostMatcher     struct{ lhs, rhs HostMatcher }
    32  	andVMMatcher       struct{ lhs, rhs VMMatcher }
    33  )
    34  
    35  func (m hostDCMatcher) Match(host *rs.Host) bool      { return m.m.MatchString(host.Hier.DC.Name) }
    36  func (m hostClusterMatcher) Match(host *rs.Host) bool { return m.m.MatchString(host.Hier.Cluster.Name) }
    37  func (m hostHostMatcher) Match(host *rs.Host) bool    { return m.m.MatchString(host.Name) }
    38  func (m vmDCMatcher) Match(vm *rs.VM) bool            { return m.m.MatchString(vm.Hier.DC.Name) }
    39  func (m vmClusterMatcher) Match(vm *rs.VM) bool       { return m.m.MatchString(vm.Hier.Cluster.Name) }
    40  func (m vmHostMatcher) Match(vm *rs.VM) bool          { return m.m.MatchString(vm.Hier.Host.Name) }
    41  func (m vmVMMatcher) Match(vm *rs.VM) bool            { return m.m.MatchString(vm.Name) }
    42  func (m orHostMatcher) Match(host *rs.Host) bool      { return m.lhs.Match(host) || m.rhs.Match(host) }
    43  func (m orVMMatcher) Match(vm *rs.VM) bool            { return m.lhs.Match(vm) || m.rhs.Match(vm) }
    44  func (m andHostMatcher) Match(host *rs.Host) bool     { return m.lhs.Match(host) && m.rhs.Match(host) }
    45  func (m andVMMatcher) Match(vm *rs.VM) bool           { return m.lhs.Match(vm) && m.rhs.Match(vm) }
    46  
    47  func newAndHostMatcher(lhs, rhs HostMatcher, others ...HostMatcher) andHostMatcher {
    48  	m := andHostMatcher{lhs: lhs, rhs: rhs}
    49  	switch len(others) {
    50  	case 0:
    51  		return m
    52  	default:
    53  		return newAndHostMatcher(m, others[0], others[1:]...)
    54  	}
    55  }
    56  
    57  func newAndVMMatcher(lhs, rhs VMMatcher, others ...VMMatcher) andVMMatcher {
    58  	m := andVMMatcher{lhs: lhs, rhs: rhs}
    59  	switch len(others) {
    60  	case 0:
    61  		return m
    62  	default:
    63  		return newAndVMMatcher(m, others[0], others[1:]...)
    64  	}
    65  }
    66  
    67  func newOrHostMatcher(lhs, rhs HostMatcher, others ...HostMatcher) orHostMatcher {
    68  	m := orHostMatcher{lhs: lhs, rhs: rhs}
    69  	switch len(others) {
    70  	case 0:
    71  		return m
    72  	default:
    73  		return newOrHostMatcher(m, others[0], others[1:]...)
    74  	}
    75  }
    76  
    77  func newOrVMMatcher(lhs, rhs VMMatcher, others ...VMMatcher) orVMMatcher {
    78  	m := orVMMatcher{lhs: lhs, rhs: rhs}
    79  	switch len(others) {
    80  	case 0:
    81  		return m
    82  	default:
    83  		return newOrVMMatcher(m, others[0], others[1:]...)
    84  	}
    85  }
    86  
    87  type (
    88  	VMIncludes   []string
    89  	HostIncludes []string
    90  )
    91  
    92  func (vi VMIncludes) Parse() (VMMatcher, error) {
    93  	var ms []VMMatcher
    94  	for _, v := range vi {
    95  		m, err := parseVMInclude(v)
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  		if m == nil {
   100  			continue
   101  		}
   102  		ms = append(ms, m)
   103  	}
   104  
   105  	switch len(ms) {
   106  	case 0:
   107  		return nil, nil
   108  	case 1:
   109  		return ms[0], nil
   110  	default:
   111  		return newOrVMMatcher(ms[0], ms[1], ms[2:]...), nil
   112  	}
   113  }
   114  
   115  func (hi HostIncludes) Parse() (HostMatcher, error) {
   116  	var ms []HostMatcher
   117  	for _, v := range hi {
   118  		m, err := parseHostInclude(v)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		if m == nil {
   123  			continue
   124  		}
   125  		ms = append(ms, m)
   126  	}
   127  
   128  	switch len(ms) {
   129  	case 0:
   130  		return nil, nil
   131  	case 1:
   132  		return ms[0], nil
   133  	default:
   134  		return newOrHostMatcher(ms[0], ms[1], ms[2:]...), nil
   135  	}
   136  }
   137  
   138  const (
   139  	datacenterIdx = iota
   140  	clusterIdx
   141  	hostIdx
   142  	vmIdx
   143  )
   144  
   145  func cleanInclude(include string) string {
   146  	return strings.Trim(include, "/")
   147  }
   148  
   149  func parseHostInclude(include string) (HostMatcher, error) {
   150  	if !isIncludeFormatValid(include) {
   151  		return nil, fmt.Errorf("bad include format: %s", include)
   152  	}
   153  
   154  	include = cleanInclude(include)
   155  	parts := strings.Split(include, "/") // /dc/clusterIdx/hostIdx
   156  	var ms []HostMatcher
   157  
   158  	for i, v := range parts {
   159  		m, err := parseSubInclude(v)
   160  		if err != nil {
   161  			return nil, err
   162  		}
   163  		switch i {
   164  		case datacenterIdx:
   165  			ms = append(ms, hostDCMatcher{m})
   166  		case clusterIdx:
   167  			ms = append(ms, hostClusterMatcher{m})
   168  		case hostIdx:
   169  			ms = append(ms, hostHostMatcher{m})
   170  		}
   171  	}
   172  
   173  	switch len(ms) {
   174  	case 0:
   175  		return nil, nil
   176  	case 1:
   177  		return ms[0], nil
   178  	default:
   179  		return newAndHostMatcher(ms[0], ms[1], ms[2:]...), nil
   180  	}
   181  }
   182  
   183  func parseVMInclude(include string) (VMMatcher, error) {
   184  	if !isIncludeFormatValid(include) {
   185  		return nil, fmt.Errorf("bad include format: %s", include)
   186  	}
   187  
   188  	include = cleanInclude(include)
   189  	parts := strings.Split(include, "/") // /dc/clusterIdx/hostIdx/vmIdx
   190  	var ms []VMMatcher
   191  
   192  	for i, v := range parts {
   193  		m, err := parseSubInclude(v)
   194  		if err != nil {
   195  			return nil, err
   196  		}
   197  		switch i {
   198  		case datacenterIdx:
   199  			ms = append(ms, vmDCMatcher{m})
   200  		case clusterIdx:
   201  			ms = append(ms, vmClusterMatcher{m})
   202  		case hostIdx:
   203  			ms = append(ms, vmHostMatcher{m})
   204  		case vmIdx:
   205  			ms = append(ms, vmVMMatcher{m})
   206  		}
   207  	}
   208  
   209  	switch len(ms) {
   210  	case 0:
   211  		return nil, nil
   212  	case 1:
   213  		return ms[0], nil
   214  	default:
   215  		return newAndVMMatcher(ms[0], ms[1], ms[2:]...), nil
   216  	}
   217  }
   218  
   219  func parseSubInclude(sub string) (matcher.Matcher, error) {
   220  	sub = strings.TrimSpace(sub)
   221  	if sub == "" || sub == "!*" {
   222  		return matcher.FALSE(), nil
   223  	}
   224  	if sub == "*" {
   225  		return matcher.TRUE(), nil
   226  	}
   227  	return matcher.NewSimplePatternsMatcher(sub)
   228  }
   229  
   230  func isIncludeFormatValid(line string) bool {
   231  	return strings.HasPrefix(line, "/")
   232  }