Skip to content
This repository has been archived by the owner on Aug 22, 2024. It is now read-only.

Commit

Permalink
Add collectors settings: add collectors settings validation when load…
Browse files Browse the repository at this point in the history
…ing YAML configuration.
  • Loading branch information
lesovsky committed May 7, 2021
1 parent 42d8249 commit 75d0703
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 0 deletions.
59 changes: 59 additions & 0 deletions internal/pgscv/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"gopkg.in/yaml.v2"
"os"
"path/filepath"
"regexp"
"time"
)

Expand Down Expand Up @@ -139,6 +140,64 @@ func (c *Config) Validate() error {
return err
}

// Validate collector settings.
err = validateCollectorSettings(c.CollectorsSettings)
if err != nil {
return err
}

return nil
}

// validateCollectorSettings validates collectors settings passed from main YAML configuration.
func validateCollectorSettings(cs model.CollectorsSettings) error {
if cs == nil || len(cs) == 0 {
return nil
}

for csName, settings := range cs {
re1 := regexp.MustCompile(`^[a-zA-Z0-9]+/[a-zA-Z0-9]+$`)
if !re1.MatchString(csName) {
return fmt.Errorf("invalid collector name: %s", csName)
}

// Validate subsystems level
for ssName, subsys := range settings.Subsystems {
re2 := regexp.MustCompilePOSIX(`^[a-zA-Z0-9_]+$`)

if !re2.MatchString(ssName) {
return fmt.Errorf("invalid subsystem name: %s", ssName)
}

if len(subsys.Metrics) > 0 && subsys.Query == "" {
return fmt.Errorf("query is not specified for: %s", ssName)
}

// Validate metrics level
reLabel := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
reMetric := regexp.MustCompile(`^[a-zA-Z0-9_]+$`)

for _, m := range subsys.Metrics {
usage := m.Usage
switch usage {
case "LABEL":
if !reLabel.MatchString(m.ShortName) {
return fmt.Errorf("invalid label name '%s'", m.ShortName)
}
case "COUNTER", "GAUGE":
if !reMetric.MatchString(m.ShortName) {
return fmt.Errorf("invalid metric name '%s'", m.ShortName)
}
if m.Description == "" {
return fmt.Errorf("metric description is not specified for %s", m.ShortName)
}
default:
return fmt.Errorf("invalid metric usage '%s'", usage)
}
}
}
}

return nil
}

Expand Down
138 changes: 138 additions & 0 deletions internal/pgscv/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,144 @@ func TestConfig_Validate(t *testing.T) {
}
}

func Test_validateCollectorSettings(t *testing.T) {
testcases := []struct {
valid bool
settings model.CollectorsSettings
}{
{valid: true, settings: nil},
{valid: true, settings: make(map[string]model.CollectorSettings)},
{
valid: true,
settings: map[string]model.CollectorSettings{
"example/example": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Query: "SELECT 'label1' as l1, 1 as v1",
Metrics: model.Metrics{
{ShortName: "l1", Usage: "LABEL", Description: "l1 description"},
{ShortName: "v1", Usage: "COUNTER", Description: "v1 description"},
},
},
"example2": {
Query: "SELECT 'label1' as l1, 1 as v1, 2 as v2",
Metrics: model.Metrics{
{ShortName: "l1", Usage: "LABEL", Description: "l1 description"},
{ShortName: "v1", Usage: "COUNTER", Description: "v1 description"},
{ShortName: "v2", Usage: "GAUGE", Description: "v2 description"},
},
},
},
},
"example/example2": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Query: "SELECT 'label1' as l1, 1 as v1",
Metrics: model.Metrics{
{ShortName: "l1", Usage: "LABEL", Description: "l1 description"},
{ShortName: "v1", Usage: "COUNTER", Description: "v1 description"},
},
},
},
},
},
},
// invalid collectors names
{valid: false, settings: map[string]model.CollectorSettings{"invalid": {}}},
{valid: false, settings: map[string]model.CollectorSettings{"invalid/": {}}},
{valid: false, settings: map[string]model.CollectorSettings{"/invalid": {}}},
{valid: false, settings: map[string]model.CollectorSettings{"example/inva:lid": {}}},
{
valid: false, // Invalid subsystem name for metric
settings: map[string]model.CollectorSettings{
"example/example": {Subsystems: map[string]model.MetricsSubsystem{"inva:lid": {}}},
},
},
{
valid: false, // No query specified when metric exists
settings: map[string]model.CollectorSettings{
"example/example": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Metrics: model.Metrics{
{ShortName: "l1", Usage: "LABEL", Description: "l1 description"},
},
},
},
},
},
},
{
valid: false, // Invalid name for label
settings: map[string]model.CollectorSettings{
"example/example": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Query: "SELECT 'label1' as l1, 1 as v1",
Metrics: model.Metrics{
{ShortName: "inva:lid", Usage: "LABEL", Description: "l1 description"},
},
},
},
},
},
},
{
valid: false, // Invalid name for metric
settings: map[string]model.CollectorSettings{
"example/example": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Query: "SELECT 'label1' as l1, 1 as v1",
Metrics: model.Metrics{
{ShortName: "inva:lid", Usage: "COUNTER", Description: "v1 description"},
},
},
},
},
},
},
{
valid: false, // Empty metric descriptor
settings: map[string]model.CollectorSettings{
"example/example": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Query: "SELECT 'label1' as l1, 1 as v1",
Metrics: model.Metrics{
{ShortName: "v1", Usage: "COUNTER"},
},
},
},
},
},
},
{
valid: false, // Invalid usage
settings: map[string]model.CollectorSettings{
"example/example": {
Subsystems: map[string]model.MetricsSubsystem{
"example1": {
Query: "SELECT 'label1' as l1, 1 as v1",
Metrics: model.Metrics{
{ShortName: "v1", Usage: "INVALID"},
},
},
},
},
},
},
}

for _, tc := range testcases {
if tc.valid {
assert.NoError(t, validateCollectorSettings(tc.settings))
} else {
assert.Error(t, validateCollectorSettings(tc.settings))
}
}
}

func Test_toggleAutoupdate(t *testing.T) {
testcases := []struct {
valid bool
Expand Down

0 comments on commit 75d0703

Please sign in to comment.