github.com/m3db/m3@v1.5.0/src/metrics/rules/validator/options.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package validator
    22  
    23  import (
    24  	"fmt"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"github.com/m3db/m3/src/metrics/aggregation"
    29  	"github.com/m3db/m3/src/metrics/filters"
    30  	"github.com/m3db/m3/src/metrics/metric"
    31  	"github.com/m3db/m3/src/metrics/policy"
    32  	"github.com/m3db/m3/src/metrics/rules/validator/namespace"
    33  	"github.com/m3db/m3/src/metrics/rules/validator/namespace/static"
    34  )
    35  
    36  const (
    37  	// By default we only support at most one binary transformation function in between
    38  	// consecutive rollup operations in a pipeline.
    39  	defaultMaxTransformationDerivativeOrder = 1
    40  
    41  	// By default we allow at most one level of rollup in a pipeline.
    42  	defaultMaxRollupLevels = 1
    43  )
    44  
    45  // MetricTypesFn determines the possible metric types based on a set of tag based filters.
    46  type MetricTypesFn func(tagFilters filters.TagFilterValueMap) ([]metric.Type, error)
    47  
    48  // Options provide a set of options for the validator.
    49  type Options interface {
    50  	// SetNamespaceValidator sets the namespace validator.
    51  	SetNamespaceValidator(value namespace.Validator) Options
    52  
    53  	// NamespaceValidator returns the namespace validator.
    54  	NamespaceValidator() namespace.Validator
    55  
    56  	// SetDefaultAllowedStoragePolicies sets the default list of allowed storage policies.
    57  	SetDefaultAllowedStoragePolicies(value []policy.StoragePolicy) Options
    58  
    59  	// SetDefaultAllowedFirstLevelAggregationTypes sets the default list of allowed first-level
    60  	// aggregation types.
    61  	SetDefaultAllowedFirstLevelAggregationTypes(value aggregation.Types) Options
    62  
    63  	// SetDefaultAllowedNonFirstLevelAggregationTypes sets the default list of allowed
    64  	// non-first-level aggregation types.
    65  	SetDefaultAllowedNonFirstLevelAggregationTypes(value aggregation.Types) Options
    66  
    67  	// SetAllowedStoragePoliciesFor sets the list of allowed storage policies for a given metric type.
    68  	SetAllowedStoragePoliciesFor(t metric.Type, policies []policy.StoragePolicy) Options
    69  
    70  	// SetAllowedFirstLevelAggregationTypesFor sets the list of allowed first-level aggregation
    71  	// types for a given metric type.
    72  	SetAllowedFirstLevelAggregationTypesFor(t metric.Type, aggTypes aggregation.Types) Options
    73  
    74  	// SetAllowedNonFirstLevelAggregationTypesFor sets the list of allowed non-first-level
    75  	// aggregation types for a given metric type.
    76  	SetAllowedNonFirstLevelAggregationTypesFor(t metric.Type, aggTypes aggregation.Types) Options
    77  
    78  	// SetMetricTypesFn sets the metric types function.
    79  	SetMetricTypesFn(value MetricTypesFn) Options
    80  
    81  	// MetricTypesFn returns the metric types function.
    82  	MetricTypesFn() MetricTypesFn
    83  
    84  	// SetMultiAggregationTypesEnabledFor sets the list of metric types that support
    85  	// multiple aggregation types.
    86  	SetMultiAggregationTypesEnabledFor(value []metric.Type) Options
    87  
    88  	// SetRequiredRollupTags sets the list of required rollup tags.
    89  	SetRequiredRollupTags(value []string) Options
    90  
    91  	// RequiredRollupTags returns the list of required rollup tags.
    92  	RequiredRollupTags() []string
    93  
    94  	// SetMaxTransformationDerivativeOrder sets the maximum supported transformation
    95  	// derivative order between rollup operations in pipelines.
    96  	SetMaxTransformationDerivativeOrder(value int) Options
    97  
    98  	// MaxTransformationDerivativeOrder returns the maximum supported transformation
    99  	// derivative order between rollup operations in pipelines..
   100  	MaxTransformationDerivativeOrder() int
   101  
   102  	// SetMaxRollupLevels sets the maximum number of rollup operations supported in pipelines.
   103  	SetMaxRollupLevels(value int) Options
   104  
   105  	// MaxRollupLevels returns the maximum number of rollup operations supported in pipelines.
   106  	MaxRollupLevels() int
   107  
   108  	// SetTagNameInvalidChars sets the list of invalid chars for a tag name.
   109  	SetTagNameInvalidChars(value []rune) Options
   110  
   111  	// CheckInvalidCharactersForTagName checks if the given tag name contains invalid characters
   112  	// returning an error if invalid character(s) present.
   113  	CheckInvalidCharactersForTagName(tagName string) error
   114  
   115  	// SetFiltersInvalidTagNames sets a list of case-insensitive tags that will
   116  	// cause metric filters to be rejected.
   117  	SetFilterInvalidTagNames(tagNames []string) Options
   118  
   119  	// CheckFilterTagNameValid returns an error if the given tag name is in the list of
   120  	// invalid tags.
   121  	CheckFilterTagNameValid(tagName string) error
   122  
   123  	// SetMetricNameInvalidChars sets the list of invalid chars for a metric name.
   124  	SetMetricNameInvalidChars(value []rune) Options
   125  
   126  	// CheckInvalidCharactersForMetricName checks if the given metric name contains invalid characters
   127  	// returning an error if invalid character(s) present.
   128  	CheckInvalidCharactersForMetricName(metricName string) error
   129  
   130  	// IsAllowedStoragePolicyFor determines whether a given storage policy is allowed for the
   131  	// given metric type.
   132  	IsAllowedStoragePolicyFor(t metric.Type, p policy.StoragePolicy) bool
   133  
   134  	// IsMultiAggregationTypesEnabledFor checks if a metric type supports multiple aggregation types.
   135  	IsMultiAggregationTypesEnabledFor(t metric.Type) bool
   136  
   137  	// IsAllowedFirstLevelAggregationTypeFor determines whether a given aggregation type is allowed
   138  	// as the first-level aggregation for the given metric type.
   139  	IsAllowedFirstLevelAggregationTypeFor(t metric.Type, aggType aggregation.Type) bool
   140  
   141  	// IsAllowedNonFirstLevelAggregationTypeFor determines whether a given aggregation type is
   142  	// allowed as the non-first-level aggregation for the given metric type.
   143  	IsAllowedNonFirstLevelAggregationTypeFor(t metric.Type, aggType aggregation.Type) bool
   144  }
   145  
   146  type validationMetadata struct {
   147  	allowedStoragePolicies       map[policy.StoragePolicy]struct{}
   148  	allowedFirstLevelAggTypes    map[aggregation.Type]struct{}
   149  	allowedNonFirstLevelAggTypes map[aggregation.Type]struct{}
   150  }
   151  
   152  type options struct {
   153  	namespaceValidator                          namespace.Validator
   154  	defaultAllowedStoragePolicies               map[policy.StoragePolicy]struct{}
   155  	defaultAllowedFirstLevelAggregationTypes    map[aggregation.Type]struct{}
   156  	defaultAllowedNonFirstLevelAggregationTypes map[aggregation.Type]struct{}
   157  	metricTypesFn                               MetricTypesFn
   158  	multiAggregationTypesEnableFor              map[metric.Type]struct{}
   159  	requiredRollupTags                          []string
   160  	maxTransformationDerivativeOrder            int
   161  	maxRollupLevels                             int
   162  	metricNameInvalidChars                      map[rune]struct{}
   163  	tagNameInvalidChars                         map[rune]struct{}
   164  	tagNameInvalidNames                         map[string]struct{}
   165  	metadatasByType                             map[metric.Type]validationMetadata
   166  }
   167  
   168  // NewOptions create a new set of validator options.
   169  func NewOptions() Options {
   170  	return &options{
   171  		multiAggregationTypesEnableFor:   map[metric.Type]struct{}{metric.TimerType: struct{}{}},
   172  		maxTransformationDerivativeOrder: defaultMaxTransformationDerivativeOrder,
   173  		maxRollupLevels:                  defaultMaxRollupLevels,
   174  		namespaceValidator:               static.NewNamespaceValidator(static.Valid),
   175  		metadatasByType:                  make(map[metric.Type]validationMetadata),
   176  	}
   177  }
   178  
   179  func (o *options) SetNamespaceValidator(value namespace.Validator) Options {
   180  	o.namespaceValidator = value
   181  	return o
   182  }
   183  
   184  func (o *options) NamespaceValidator() namespace.Validator {
   185  	return o.namespaceValidator
   186  }
   187  
   188  func (o *options) SetDefaultAllowedStoragePolicies(value []policy.StoragePolicy) Options {
   189  	o.defaultAllowedStoragePolicies = toStoragePolicySet(value)
   190  	return o
   191  }
   192  
   193  func (o *options) SetDefaultAllowedFirstLevelAggregationTypes(value aggregation.Types) Options {
   194  	o.defaultAllowedFirstLevelAggregationTypes = toAggregationTypeSet(value)
   195  	return o
   196  }
   197  
   198  func (o *options) SetDefaultAllowedNonFirstLevelAggregationTypes(value aggregation.Types) Options {
   199  	o.defaultAllowedNonFirstLevelAggregationTypes = toAggregationTypeSet(value)
   200  	return o
   201  }
   202  
   203  func (o *options) SetAllowedStoragePoliciesFor(t metric.Type, policies []policy.StoragePolicy) Options {
   204  	metadata := o.findOrCreateMetadata(t)
   205  	metadata.allowedStoragePolicies = toStoragePolicySet(policies)
   206  	o.metadatasByType[t] = metadata
   207  	return o
   208  }
   209  
   210  func (o *options) SetAllowedFirstLevelAggregationTypesFor(t metric.Type, aggTypes aggregation.Types) Options {
   211  	metadata := o.findOrCreateMetadata(t)
   212  	metadata.allowedFirstLevelAggTypes = toAggregationTypeSet(aggTypes)
   213  	o.metadatasByType[t] = metadata
   214  	return o
   215  }
   216  
   217  func (o *options) SetAllowedNonFirstLevelAggregationTypesFor(t metric.Type, aggTypes aggregation.Types) Options {
   218  	metadata := o.findOrCreateMetadata(t)
   219  	metadata.allowedNonFirstLevelAggTypes = toAggregationTypeSet(aggTypes)
   220  	o.metadatasByType[t] = metadata
   221  	return o
   222  }
   223  
   224  func (o *options) SetMetricTypesFn(value MetricTypesFn) Options {
   225  	o.metricTypesFn = value
   226  	return o
   227  }
   228  
   229  func (o *options) MetricTypesFn() MetricTypesFn {
   230  	return o.metricTypesFn
   231  }
   232  
   233  func (o *options) SetMultiAggregationTypesEnabledFor(value []metric.Type) Options {
   234  	o.multiAggregationTypesEnableFor = toMetricTypeSet(value)
   235  	return o
   236  }
   237  
   238  func (o *options) SetRequiredRollupTags(value []string) Options {
   239  	requiredRollupTags := make([]string, len(value))
   240  	copy(requiredRollupTags, value)
   241  	o.requiredRollupTags = requiredRollupTags
   242  	return o
   243  }
   244  
   245  func (o *options) RequiredRollupTags() []string {
   246  	return o.requiredRollupTags
   247  }
   248  
   249  func (o *options) SetMaxTransformationDerivativeOrder(value int) Options {
   250  	o.maxTransformationDerivativeOrder = value
   251  	return o
   252  }
   253  
   254  func (o *options) MaxTransformationDerivativeOrder() int {
   255  	return o.maxTransformationDerivativeOrder
   256  }
   257  
   258  func (o *options) SetMaxRollupLevels(value int) Options {
   259  	o.maxRollupLevels = value
   260  	return o
   261  }
   262  
   263  func (o *options) MaxRollupLevels() int {
   264  	return o.maxRollupLevels
   265  }
   266  
   267  func (o *options) SetTagNameInvalidChars(values []rune) Options {
   268  	tagNameInvalidChars := make(map[rune]struct{}, len(values))
   269  	for _, v := range values {
   270  		tagNameInvalidChars[v] = struct{}{}
   271  	}
   272  	o.tagNameInvalidChars = tagNameInvalidChars
   273  	return o
   274  }
   275  
   276  func (o *options) CheckInvalidCharactersForTagName(tagName string) error {
   277  	return validateChars(tagName, o.tagNameInvalidChars)
   278  }
   279  
   280  func (o *options) SetFilterInvalidTagNames(tagNames []string) Options {
   281  	o.tagNameInvalidNames = make(map[string]struct{}, len(tagNames))
   282  	for _, n := range tagNames {
   283  		o.tagNameInvalidNames[strings.ToLower(n)] = struct{}{}
   284  	}
   285  	return o
   286  }
   287  
   288  func (o *options) CheckFilterTagNameValid(tagName string) error {
   289  	if _, ok := o.tagNameInvalidNames[strings.ToLower(tagName)]; ok {
   290  		return fmt.Errorf("'%s' in invalid tag name list", tagName)
   291  	}
   292  	return nil
   293  }
   294  
   295  func (o *options) SetMetricNameInvalidChars(values []rune) Options {
   296  	metricNameInvalidChars := make(map[rune]struct{}, len(values))
   297  	for _, v := range values {
   298  		metricNameInvalidChars[v] = struct{}{}
   299  	}
   300  	o.metricNameInvalidChars = metricNameInvalidChars
   301  	return o
   302  }
   303  
   304  func (o *options) CheckInvalidCharactersForMetricName(metricName string) error {
   305  	return validateChars(metricName, o.metricNameInvalidChars)
   306  }
   307  
   308  func (o *options) IsAllowedStoragePolicyFor(t metric.Type, p policy.StoragePolicy) bool {
   309  	if metadata, exists := o.metadatasByType[t]; exists {
   310  		_, found := metadata.allowedStoragePolicies[p]
   311  		return found
   312  	}
   313  	_, found := o.defaultAllowedStoragePolicies[p]
   314  	return found
   315  }
   316  
   317  func (o *options) IsMultiAggregationTypesEnabledFor(t metric.Type) bool {
   318  	_, exists := o.multiAggregationTypesEnableFor[t]
   319  	return exists
   320  }
   321  
   322  func (o *options) IsAllowedFirstLevelAggregationTypeFor(t metric.Type, aggType aggregation.Type) bool {
   323  	if metadata, exists := o.metadatasByType[t]; exists {
   324  		_, found := metadata.allowedFirstLevelAggTypes[aggType]
   325  		return found
   326  	}
   327  	_, found := o.defaultAllowedFirstLevelAggregationTypes[aggType]
   328  	return found
   329  }
   330  
   331  func (o *options) IsAllowedNonFirstLevelAggregationTypeFor(t metric.Type, aggType aggregation.Type) bool {
   332  	if metadata, exists := o.metadatasByType[t]; exists {
   333  		_, found := metadata.allowedNonFirstLevelAggTypes[aggType]
   334  		return found
   335  	}
   336  	_, found := o.defaultAllowedNonFirstLevelAggregationTypes[aggType]
   337  	return found
   338  }
   339  
   340  func (o *options) findOrCreateMetadata(t metric.Type) validationMetadata {
   341  	if metadata, found := o.metadatasByType[t]; found {
   342  		return metadata
   343  	}
   344  	return validationMetadata{
   345  		allowedStoragePolicies:       o.defaultAllowedStoragePolicies,
   346  		allowedFirstLevelAggTypes:    o.defaultAllowedFirstLevelAggregationTypes,
   347  		allowedNonFirstLevelAggTypes: o.defaultAllowedNonFirstLevelAggregationTypes,
   348  	}
   349  }
   350  
   351  func toStoragePolicySet(policies []policy.StoragePolicy) map[policy.StoragePolicy]struct{} {
   352  	m := make(map[policy.StoragePolicy]struct{}, len(policies))
   353  	for _, p := range policies {
   354  		m[p] = struct{}{}
   355  	}
   356  	return m
   357  }
   358  
   359  func toAggregationTypeSet(aggTypes aggregation.Types) map[aggregation.Type]struct{} {
   360  	m := make(map[aggregation.Type]struct{}, len(aggTypes))
   361  	for _, t := range aggTypes {
   362  		m[t] = struct{}{}
   363  	}
   364  	return m
   365  }
   366  
   367  func toMetricTypeSet(metricTypes []metric.Type) map[metric.Type]struct{} {
   368  	m := make(map[metric.Type]struct{}, len(metricTypes))
   369  	for _, mt := range metricTypes {
   370  		m[mt] = struct{}{}
   371  	}
   372  	return m
   373  }
   374  
   375  func validateChars(str string, invalidChars map[rune]struct{}) error {
   376  	if len(invalidChars) == 0 {
   377  		return nil
   378  	}
   379  
   380  	// Validate that given string doesn't contain an invalid character.
   381  	for _, char := range str {
   382  		if _, exists := invalidChars[char]; exists {
   383  			return fmt.Errorf("%s contains invalid character %s", str, strconv.QuoteRune(char))
   384  		}
   385  	}
   386  	return nil
   387  }