From db3367e83f680a426b134515ab04305d1facf597 Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Sat, 6 Jun 2015 09:55:22 +0200 Subject: [PATCH] config: ensure correct labelname in JSON target group. --- .../client_golang/model/labelname.go | 14 ++++++++++++++ .../client_golang/model/labelset.go | 19 +++++++++++++++++++ config/config_test.go | 17 +++++++++++++++++ config/testdata/labelname2.bad.yml | 3 +++ config/testdata/tgroup.bad.json | 7 +++++++ 5 files changed, 60 insertions(+) create mode 100644 config/testdata/labelname2.bad.yml create mode 100644 config/testdata/tgroup.bad.json diff --git a/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go b/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go index 7efbd9f41..ed6915ce8 100644 --- a/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go +++ b/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go @@ -14,6 +14,7 @@ package model import ( + "encoding/json" "fmt" "regexp" "strings" @@ -81,6 +82,19 @@ func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } +// UnmarshalJSON implements the json.Unmarshaler interface. +func (ln *LabelName) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + if !LabelNameRE.MatchString(s) { + return fmt.Errorf("%q is not a valid label name", s) + } + *ln = LabelName(s) + return nil +} + // LabelNames is a sortable LabelName slice. In implements sort.Interface. type LabelNames []LabelName diff --git a/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelset.go b/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelset.go index b1b54fba3..d04d84320 100644 --- a/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelset.go +++ b/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelset.go @@ -14,6 +14,7 @@ package model import ( + "encoding/json" "fmt" "sort" "strings" @@ -62,3 +63,21 @@ func (l LabelSet) MergeFromMetric(m Metric) { l[k] = v } } + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (l *LabelSet) UnmarshalJSON(b []byte) error { + var m map[LabelName]LabelValue + if err := json.Unmarshal(b, &m); err != nil { + return err + } + // encoding/json only unmarshals maps of the form map[string]T. It does not + // detect that LabelName is a string and does not call its UnmarshalJSON method. + // Thus we have to replicate the behavior here. + for ln := range m { + if !LabelNameRE.MatchString(string(ln)) { + return fmt.Errorf("%q is not a valid label name", ln) + } + } + *l = LabelSet(m) + return nil +} diff --git a/config/config_test.go b/config/config_test.go index 61aeb7f84..f907eb729 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,6 +1,8 @@ package config import ( + "encoding/json" + "io/ioutil" "reflect" "regexp" "strings" @@ -149,6 +151,9 @@ var expectedErrors = []struct { }, { filename: "labelname.bad.yml", errMsg: `"not$allowed" is not a valid label name`, + }, { + filename: "labelname2.bad.yml", + errMsg: `"not:allowed" is not a valid label name`, }, { filename: "regex.bad.yml", errMsg: "error parsing regexp", @@ -170,3 +175,15 @@ func TestBadConfigs(t *testing.T) { } } } + +func TestBadTargetGroup(t *testing.T) { + content, err := ioutil.ReadFile("testdata/tgroup.bad.json") + if err != nil { + t.Fatal(err) + } + var tg TargetGroup + err = json.Unmarshal(content, &tg) + if err == nil { + t.Errorf("Expected unmarshal error but got none.") + } +} diff --git a/config/testdata/labelname2.bad.yml b/config/testdata/labelname2.bad.yml new file mode 100644 index 000000000..30da44b17 --- /dev/null +++ b/config/testdata/labelname2.bad.yml @@ -0,0 +1,3 @@ +global: + labels: + 'not:allowed': value diff --git a/config/testdata/tgroup.bad.json b/config/testdata/tgroup.bad.json new file mode 100644 index 000000000..6050ed9c5 --- /dev/null +++ b/config/testdata/tgroup.bad.json @@ -0,0 +1,7 @@ +{ + "targets": ["1.2.3.4:9100"], + "labels": { + "some_valid_label": "foo", + "oops:this-label-is-invalid": "bar" + } +}