From 3db95a9ece580ba0918ab63e08adeaa404091bd7 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 10 Apr 2018 10:05:34 +0300 Subject: [PATCH 1/3] make public org id configurable so that org 0 is invalid and we don't accidentally publish public data when we forget to set the proper value. --- docs/http-api.md | 6 +++--- docs/multi-tenancy.md | 2 +- idx/idx.go | 2 +- idx/memory/memory.go | 2 +- metrictank-sample.ini | 4 ++++ metrictank.go | 7 +++++++ 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/http-api.md b/docs/http-api.md index f00b2cef87..169e0d77c8 100644 --- a/docs/http-api.md +++ b/docs/http-api.md @@ -35,7 +35,7 @@ POST /metrics/index.json * header `X-Org-Id` required -Returns metrics stored under the given org, as well as public data under org 0 (see [multi-tenancy](https://github.com/grafana/metrictank/blob/master/docs/multi-tenancy.md)) +Returns metrics stored under the given org, as well as public data (see [multi-tenancy](https://github.com/grafana/metrictank/blob/master/docs/multi-tenancy.md)) #### Example @@ -56,7 +56,7 @@ POST /metrics/find * format: json, treejson, completer, pickle, or msgpack. (defaults to json) * jsonp -Returns metrics which match the query and are stored under the given org or are public data under org 0 (see [multi-tenancy](https://github.com/grafana/metrictank/blob/master/docs/multi-tenancy.md)) +Returns metrics which match the query and are stored under the given org or are public data (see [multi-tenancy](https://github.com/grafana/metrictank/blob/master/docs/multi-tenancy.md)) the completer format is for completion UI's such as graphite-web. json and treejson are the same. @@ -112,7 +112,7 @@ POST /render If metrictank doesn't have a requested function, it always proxies to graphite, irrespective of this setting. -Data queried for must be stored under the given org or be public data under org 0 (see [multi-tenancy](https://github.com/grafana/metrictank/blob/master/docs/multi-tenancy.md)) +Data queried for must be stored under the given org or be public data (see [multi-tenancy](https://github.com/grafana/metrictank/blob/master/docs/multi-tenancy.md)) #### Example diff --git a/docs/multi-tenancy.md b/docs/multi-tenancy.md index e8bab070b2..146570f43e 100644 --- a/docs/multi-tenancy.md +++ b/docs/multi-tenancy.md @@ -10,4 +10,4 @@ A metrictank based stack is multi-tenant. Here's how it works: * For a secure setup, you must make sure these headers cannot be specified by users. You may need to run something in front to set the header correctly after authentication (e.g. [tsdb-gw](https://github.com/raintank/tsdb-gw) * orgs can only see the data that lives under their org-id, and also public data -* public data is stored under orgId 0 and is visible to everyone. +* using the `public-org` setting, you can specify an org-id which holds public data. diff --git a/idx/idx.go b/idx/idx.go index 275d51ffe2..b14e447f35 100644 --- a/idx/idx.go +++ b/idx/idx.go @@ -13,7 +13,7 @@ import ( schema "gopkg.in/raintank/schema.v1" ) -const OrgIdPublic = 0 +var OrgIdPublic = 0 var ( BothBranchAndLeaf = errors.New("node can't be both branch and leaf") diff --git a/idx/memory/memory.go b/idx/memory/memory.go index 31d8e8eb65..4b0cf7d8de 100755 --- a/idx/memory/memory.go +++ b/idx/memory/memory.go @@ -836,7 +836,7 @@ func (m *MemoryIdx) Find(orgId int, pattern string, from int64) ([]idx.Node, err if err != nil { return nil, err } - if orgId != idx.OrgIdPublic { + if orgId != idx.OrgIdPublic && idx.OrgIdPublic > 0 { publicNodes, err := m.find(idx.OrgIdPublic, pattern) if err != nil { return nil, err diff --git a/metrictank-sample.ini b/metrictank-sample.ini index 9b6392e9f2..c1c70fd178 100644 --- a/metrictank-sample.ini +++ b/metrictank-sample.ini @@ -24,6 +24,10 @@ gc-interval = 1h # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1h +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 + ## metric data storage in cassandra ## # see https://github.com/grafana/metrictank/blob/master/docs/cassandra.md for more details diff --git a/metrictank.go b/metrictank.go index 7e4fb1d9c0..1301fbd914 100644 --- a/metrictank.go +++ b/metrictank.go @@ -62,6 +62,7 @@ var ( metricMaxStaleStr = flag.String("metric-max-stale", "6h", "max age for a metric before to be considered stale and to be purged from memory.") gcIntervalStr = flag.String("gc-interval", "1h", "Interval to run garbage collection job.") warmUpPeriodStr = flag.String("warm-up-period", "1h", "duration before secondary nodes start serving requests") + publicOrg = flag.Int("public-org", 0, "org Id for publically (any org) accessible data. leave 0 to disable") // Cassandra: cassandraAddrs = flag.String("cassandra-addrs", "localhost", "cassandra host (may be given multiple times as comma-separated list)") @@ -323,6 +324,12 @@ func main() { ***********************************/ pre := time.Now() + if *publicOrg < 0 { + log.Fatal(4, "public-org cannot be <0") + } + + idx.OrgIdPublic = *publicOrg + if memory.Enabled { if metricIndex != nil { log.Fatal(4, "Only 1 metricIndex handler can be enabled.") From b25d02c972042b8a6e892a4057c4d962d2bfca9e Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 10 Apr 2018 10:08:19 +0300 Subject: [PATCH 2/3] ./scripts/dev/sync-configs.sh --- docker/docker-chaos/metrictank.ini | 4 ++++ docker/docker-cluster/metrictank.ini | 4 ++++ docker/docker-dev-custom-cfg-kafka/metrictank.ini | 4 ++++ docs/config.md | 3 +++ scripts/config/metrictank-docker.ini | 4 ++++ scripts/config/metrictank-package.ini | 4 ++++ 6 files changed, 23 insertions(+) diff --git a/docker/docker-chaos/metrictank.ini b/docker/docker-chaos/metrictank.ini index 465a355c62..2a51221143 100644 --- a/docker/docker-chaos/metrictank.ini +++ b/docker/docker-chaos/metrictank.ini @@ -21,6 +21,10 @@ gc-interval = 1h # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1s +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 + ## metric data storage in cassandra ## # see https://github.com/grafana/metrictank/blob/master/docs/cassandra.md for more details diff --git a/docker/docker-cluster/metrictank.ini b/docker/docker-cluster/metrictank.ini index eda744ad05..a5c0609929 100644 --- a/docker/docker-cluster/metrictank.ini +++ b/docker/docker-cluster/metrictank.ini @@ -21,6 +21,10 @@ gc-interval = 1h # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1s +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 + ## metric data storage in cassandra ## # see https://github.com/grafana/metrictank/blob/master/docs/cassandra.md for more details diff --git a/docker/docker-dev-custom-cfg-kafka/metrictank.ini b/docker/docker-dev-custom-cfg-kafka/metrictank.ini index 788c666e1c..253820099a 100644 --- a/docker/docker-dev-custom-cfg-kafka/metrictank.ini +++ b/docker/docker-dev-custom-cfg-kafka/metrictank.ini @@ -21,6 +21,10 @@ gc-interval = 1h # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1h +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 + ## metric data storage in cassandra ## # see https://github.com/grafana/metrictank/blob/master/docs/cassandra.md for more details diff --git a/docs/config.md b/docs/config.md index ee77116f64..81cb796f62 100644 --- a/docs/config.md +++ b/docs/config.md @@ -49,6 +49,9 @@ gc-interval = 1h # shorter warmup means metrictank will need to query cassandra more if it doesn't have requested data yet. # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1h +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 ``` ## metric data storage in cassandra ## diff --git a/scripts/config/metrictank-docker.ini b/scripts/config/metrictank-docker.ini index f587422706..ad4ba1591e 100644 --- a/scripts/config/metrictank-docker.ini +++ b/scripts/config/metrictank-docker.ini @@ -21,6 +21,10 @@ gc-interval = 1h # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1h +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 + ## metric data storage in cassandra ## # see https://github.com/grafana/metrictank/blob/master/docs/cassandra.md for more details diff --git a/scripts/config/metrictank-package.ini b/scripts/config/metrictank-package.ini index 3a169a1fe0..2c6d0cb190 100644 --- a/scripts/config/metrictank-package.ini +++ b/scripts/config/metrictank-package.ini @@ -21,6 +21,10 @@ gc-interval = 1h # in clusters, best to assure the primary has saved all the data that a newly warmup instance will need to query, to prevent gaps in charts warm-up-period = 1h +# org Id for publically (any org) accessible data +# leave at 0 to disable. +public-org = 0 + ## metric data storage in cassandra ## # see https://github.com/grafana/metrictank/blob/master/docs/cassandra.md for more details From e72b7e4ed26140562e3bbac45eaba0bad23f123a Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 10 Apr 2018 10:47:30 +0300 Subject: [PATCH 3/3] make tests for OrgIdPublic work --- idx/cassandra/cassandra_test.go | 5 +++++ idx/memory/memory_test.go | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/idx/cassandra/cassandra_test.go b/idx/cassandra/cassandra_test.go index ee0db72744..f8f29be9f3 100644 --- a/idx/cassandra/cassandra_test.go +++ b/idx/cassandra/cassandra_test.go @@ -122,6 +122,9 @@ func getMetricData(orgId, depth, count, interval int, prefix string) []*schema.M } func TestGetAddKey(t *testing.T) { + idx.OrgIdPublic = 100 + defer func() { idx.OrgIdPublic = 0 }() + ix := New() initForTests(ix) @@ -256,6 +259,8 @@ func TestAddToWriteQueue(t *testing.T) { } func TestFind(t *testing.T) { + idx.OrgIdPublic = 100 + defer func() { idx.OrgIdPublic = 0 }() ix := New() initForTests(ix) for _, s := range getMetricData(idx.OrgIdPublic, 2, 5, 10, "metric.demo") { diff --git a/idx/memory/memory_test.go b/idx/memory/memory_test.go index e3c87d8b05..e64d216a9e 100644 --- a/idx/memory/memory_test.go +++ b/idx/memory/memory_test.go @@ -83,6 +83,9 @@ func TestGetAddKey(t *testing.T) { } func testGetAddKey(t *testing.T) { + idx.OrgIdPublic = 100 + defer func() { idx.OrgIdPublic = 0 }() + ix := New() ix.Init() @@ -126,6 +129,9 @@ func TestFind(t *testing.T) { } func testFind(t *testing.T) { + idx.OrgIdPublic = 100 + defer func() { idx.OrgIdPublic = 0 }() + ix := New() ix.Init() for _, s := range getMetricData(idx.OrgIdPublic, 2, 5, 10, "metric.demo", false) { @@ -253,6 +259,9 @@ func TestDelete(t *testing.T) { } func testDelete(t *testing.T) { + idx.OrgIdPublic = 100 + defer func() { idx.OrgIdPublic = 0 }() + ix := New() ix.Init() @@ -268,6 +277,9 @@ func testDelete(t *testing.T) { } func TestDeleteTagged(t *testing.T) { + idx.OrgIdPublic = 100 + defer func() { idx.OrgIdPublic = 0 }() + ix := New() ix.Init()