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 }