Add validation for graphite config templates and tags
parent
b55981f090
commit
fed8d67946
|
@ -97,5 +97,11 @@ func (c *Config) Validate() error {
|
|||
} else if c.HintedHandoff.Dir == "" {
|
||||
return errors.New("HintedHandoff.Dir must be specified")
|
||||
}
|
||||
|
||||
for _, g := range c.Graphites {
|
||||
if err := g.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid graphite config: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package graphite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdb/influxdb/toml"
|
||||
|
@ -14,15 +15,6 @@ const (
|
|||
// DefaultDatabase is the default database if none is specified.
|
||||
DefaultDatabase = "graphite"
|
||||
|
||||
// DefaultNameSeparator represents the default field separator.
|
||||
DefaultNameSeparator = "."
|
||||
|
||||
// DefaultNameSchema represents the default schema of the name.
|
||||
DefaultNameSchema = "measurement"
|
||||
|
||||
// By default unnamed fields from metrics will be ignored.
|
||||
DefaultIgnoreUnnamed = true
|
||||
|
||||
// DefaultProtocol is the default IP protocol used by the Graphite input.
|
||||
DefaultProtocol = "tcp"
|
||||
|
||||
|
@ -36,10 +28,6 @@ type Config struct {
|
|||
Database string `toml:"database"`
|
||||
Enabled bool `toml:"enabled"`
|
||||
Protocol string `toml:"protocol"`
|
||||
NamePosition string `toml:"name-position"`
|
||||
NameSchema string `toml:"name-schema"`
|
||||
NameSeparator string `toml:"name-separator"`
|
||||
IgnoreUnnamed bool `toml:"ignore-unnamed"`
|
||||
BatchSize int `toml:"batch-size"`
|
||||
BatchTimeout toml.Duration `toml:"batch-timeout"`
|
||||
ConsistencyLevel string `toml:"consistency-level"`
|
||||
|
@ -53,9 +41,6 @@ func NewConfig() Config {
|
|||
BindAddress: DefaultBindAddress,
|
||||
Database: DefaultDatabase,
|
||||
Protocol: DefaultProtocol,
|
||||
NameSchema: DefaultNameSchema,
|
||||
NameSeparator: DefaultNameSeparator,
|
||||
IgnoreUnnamed: DefaultIgnoreUnnamed,
|
||||
ConsistencyLevel: DefaultConsistencyLevel,
|
||||
}
|
||||
}
|
||||
|
@ -73,12 +58,6 @@ func (c *Config) WithDefaults() *Config {
|
|||
if d.Protocol == "" {
|
||||
d.Protocol = DefaultProtocol
|
||||
}
|
||||
if d.NameSchema == "" {
|
||||
d.NameSchema = DefaultNameSchema
|
||||
}
|
||||
if d.NameSeparator == "" {
|
||||
d.NameSeparator = DefaultNameSeparator
|
||||
}
|
||||
if d.ConsistencyLevel == "" {
|
||||
d.ConsistencyLevel = DefaultConsistencyLevel
|
||||
}
|
||||
|
@ -93,3 +72,116 @@ func (c *Config) DefaultTags() tsdb.Tags {
|
|||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func (c *Config) Validate() error {
|
||||
if err := c.validateTemplates(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.validateTags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) validateTemplates() error {
|
||||
for i, t := range c.Templates {
|
||||
parts := strings.Fields(t)
|
||||
// Ensure template string is non-empty
|
||||
if len(parts) == 0 {
|
||||
return fmt.Errorf("missing template at position: %d", i)
|
||||
}
|
||||
if len(parts) == 1 && parts[0] == "" {
|
||||
return fmt.Errorf("missing template at position: %d", i)
|
||||
}
|
||||
|
||||
if len(parts) > 3 {
|
||||
return fmt.Errorf("invalid template format: '%s'", t)
|
||||
}
|
||||
|
||||
template := t
|
||||
filter := ""
|
||||
tags := ""
|
||||
if len(parts) >= 2 {
|
||||
filter = parts[0]
|
||||
template = parts[1]
|
||||
}
|
||||
|
||||
if len(parts) == 3 {
|
||||
tags = parts[2]
|
||||
}
|
||||
|
||||
// Validate the template has one and only one measurement
|
||||
if err := c.validateTemplate(template); err != nil {
|
||||
return err
|
||||
}
|
||||
// Validate filter expression is valid
|
||||
if err := c.validateFilter(filter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tags != "" {
|
||||
// Validate tags
|
||||
for _, tagStr := range strings.Split(tags, ",") {
|
||||
if err := c.validateTag(tagStr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) validateTags() error {
|
||||
for _, t := range c.Tags {
|
||||
if err := c.validateTag(t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) validateTemplate(template string) error {
|
||||
hasMeasurement := false
|
||||
for _, p := range strings.Split(template, ".") {
|
||||
if p == "measurement" || p == "measurement*" {
|
||||
if hasMeasurement {
|
||||
return fmt.Errorf("multiple measurements in template `%s`", template)
|
||||
}
|
||||
hasMeasurement = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasMeasurement {
|
||||
return fmt.Errorf("no measurement in template `%s`", template)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) validateFilter(filter string) error {
|
||||
for _, p := range strings.Split(filter, ".") {
|
||||
if p == "" {
|
||||
return fmt.Errorf("filter contains blank section: %s", filter)
|
||||
}
|
||||
|
||||
if strings.Contains(p, "*") && p != "*" {
|
||||
return fmt.Errorf("invalid filter wildcard section: %s", filter)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) validateTag(keyValue string) error {
|
||||
parts := strings.Split(keyValue, "=")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid template tags: '%s'", keyValue)
|
||||
}
|
||||
|
||||
if parts[0] == "" || parts[1] == "" {
|
||||
return fmt.Errorf("invalid template tags: %s'", keyValue)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@ bind-address = ":8080"
|
|||
database = "mydb"
|
||||
enabled = true
|
||||
protocol = "tcp"
|
||||
name-schema= "measurement"
|
||||
ignore-unnamed = true
|
||||
name-separator = "."
|
||||
batch-size=100
|
||||
batch-timeout="1s"
|
||||
consistency-level="one"
|
||||
|
@ -37,12 +34,6 @@ tags=["region=us-east"]
|
|||
t.Fatalf("unexpected graphite enabled: %v", c.Enabled)
|
||||
} else if c.Protocol != "tcp" {
|
||||
t.Fatalf("unexpected graphite protocol: %s", c.Protocol)
|
||||
} else if c.NameSchema != "measurement" {
|
||||
t.Fatalf("unexpected graphite name schema: %s", c.NameSchema)
|
||||
} else if c.IgnoreUnnamed != true {
|
||||
t.Fatalf("unexpected ignore-unnamed: %v", c.IgnoreUnnamed)
|
||||
} else if c.NameSeparator != "." {
|
||||
t.Fatalf("unexpected graphite name separator: %s", c.NameSeparator)
|
||||
} else if c.BatchSize != 100 {
|
||||
t.Fatalf("unexpected graphite batch size: %d", c.BatchSize)
|
||||
} else if time.Duration(c.BatchTimeout) != time.Second {
|
||||
|
@ -58,3 +49,106 @@ tags=["region=us-east"]
|
|||
t.Fatalf("unexpected graphite templates setting: %s", c.ConsistencyLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidateEmptyTemplate(t *testing.T) {
|
||||
c := graphite.NewConfig()
|
||||
c.Templates = []string{""}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{" "}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidateTooManyField(t *testing.T) {
|
||||
c := graphite.NewConfig()
|
||||
c.Templates = []string{"a measurement b c"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidateTemplatePatterns(t *testing.T) {
|
||||
c := graphite.NewConfig()
|
||||
c.Templates = []string{"measurement.measurement"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{"*measurement"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{".host.region"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidateFilter(t *testing.T) {
|
||||
c := graphite.NewConfig()
|
||||
c.Templates = []string{".server measurement*"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{". .server measurement*"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{"server* measurement*"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidateTemplateTags(t *testing.T) {
|
||||
c := graphite.NewConfig()
|
||||
c.Templates = []string{"*.server measurement* foo"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{"*.server measurement* foo=bar="}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{"*.server measurement* foo=bar,"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Templates = []string{"*.server measurement* ="}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidateDefaultTags(t *testing.T) {
|
||||
c := graphite.NewConfig()
|
||||
c.Tags = []string{"foo"}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Tags = []string{"foo=bar="}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Tags = []string{"foo=bar", ""}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
|
||||
c.Tags = []string{"="}
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Errorf("config validate expected error. got nil")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue