diff --git a/README.md b/README.md index e12300f..2d3c054 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,12 @@ tenant: # https://grafana.com/docs/mimir/latest/configure/about-tenant-ids/ # env: CT_TENANT_PREFIX prefix: foobar- + + # If true will use the tenant ID of the inbound request as the prefix of the new tenant id. + # Will be automatically suffixed with a `-` character. + # https://grafana.com/docs/mimir/latest/configure/about-tenant-ids/ + # env: CT_TENANT_PREFIX + prefix_prefer_source: false ``` ### Prometheus configuration example diff --git a/VERSION b/VERSION index 81f3632..89c881b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.3 +1.12.4 diff --git a/config.go b/config.go index 9b02490..d03cd00 100644 --- a/config.go +++ b/config.go @@ -37,12 +37,13 @@ type config struct { } Tenant struct { - Label string `env:"CT_TENANT_LABEL"` - Prefix string `yaml:"prefix" env:"CT_TENANT_PREFIX"` - LabelRemove bool `yaml:"label_remove" env:"CT_TENANT_LABEL_REMOVE"` - Header string `env:"CT_TENANT_HEADER"` - Default string `env:"CT_TENANT_DEFAULT"` - AcceptAll bool `yaml:"accept_all" env:"CT_TENANT_ACCEPT_ALL"` + Label string `env:"CT_TENANT_LABEL"` + Prefix string `yaml:"prefix" env:"CT_TENANT_PREFIX"` + PrefixPreferSource bool `yaml:"prefix_prefer_source" env:"CT_TENANT_PREFIX_PREFER_SOURCE` + LabelRemove bool `yaml:"label_remove" env:"CT_TENANT_LABEL_REMOVE"` + Header string `env:"CT_TENANT_HEADER"` + Default string `env:"CT_TENANT_DEFAULT"` + AcceptAll bool `yaml:"accept_all" env:"CT_TENANT_ACCEPT_ALL"` } pipeIn *fhu.InmemoryListener diff --git a/config.yml b/config.yml index c74e0f7..c7fc1e0 100644 --- a/config.yml +++ b/config.yml @@ -22,6 +22,7 @@ log_response_errors: true tenant: label: tenant prefix: "" + prefix_prefer_source: false label_remove: true header: X-Scope-OrgID default: "" diff --git a/deploy/k8s/chart/Chart.yaml b/deploy/k8s/chart/Chart.yaml index 38ac7e4..14f0927 100644 --- a/deploy/k8s/chart/Chart.yaml +++ b/deploy/k8s/chart/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 description: A Helm Chart for cortex-tenant name: cortex-tenant -version: 0.4.0 # This is the chart version -appVersion: 1.11.0 # version number of the application being deployed. +version: 0.4.1 # This is the chart version +appVersion: 1.12.4 # version number of the application being deployed. type: application sources: - https://github.com/blind-oracle/cortex-tenant diff --git a/deploy/k8s/chart/templates/configmap.yaml b/deploy/k8s/chart/templates/configmap.yaml index 4d518cd..7bed384 100644 --- a/deploy/k8s/chart/templates/configmap.yaml +++ b/deploy/k8s/chart/templates/configmap.yaml @@ -26,6 +26,7 @@ data: tenant: label: {{ .Values.config.tenant.label }} prefix: {{ .Values.config.tenant.prefix }} + prefix_prefer_source: {{ .Values.config.tenant.prefix_prefer_source }} label_remove: {{ .Values.config.tenant.label_remove }} header: {{ .Values.config.tenant.header }} default: {{ .Values.config.tenant.default }} diff --git a/deploy/k8s/chart/values.schema.json b/deploy/k8s/chart/values.schema.json index 9b1458d..c28d7c7 100644 --- a/deploy/k8s/chart/values.schema.json +++ b/deploy/k8s/chart/values.schema.json @@ -265,6 +265,12 @@ "title": "Prefix", "description": "Optional hard-coded prefix with delimeter for all tenant values" }, + "prefix_prefer_source": { + "type": "boolean", + "title": "Prefix Prefer Source", + "description": "If true will use the tenant ID of the inbound request as the prefix of the new tenant id.", + "default": false + }, "label_remove": { "type": "boolean", "title": "Label Remove", diff --git a/deploy/k8s/chart/values.yaml b/deploy/k8s/chart/values.yaml index 3a9326a..e0c2343 100644 --- a/deploy/k8s/chart/values.yaml +++ b/deploy/k8s/chart/values.yaml @@ -105,6 +105,10 @@ config: # https://grafana.com/docs/mimir/latest/configure/about-tenant-ids/ # (env: `CT_TENANT_PREFIX`) prefix: "" + # -- If true will use the tenant ID of the inbound request as the prefix of the new tenant id. + # Will be automatically suffixed with a `-` character. + # (env: `CT_TENANT_PREFIX_PREFER_SOURCE`) + prefix_prefer_source: false # -- Whether to remove the tenant label from the request # (env: `CT_TENANT_LABEL_REMOVE`) label_remove: false diff --git a/deploy/k8s/manifests/config-file-configmap.yml b/deploy/k8s/manifests/config-file-configmap.yml index 6c8eaf8..4ffa9b7 100644 --- a/deploy/k8s/manifests/config-file-configmap.yml +++ b/deploy/k8s/manifests/config-file-configmap.yml @@ -42,6 +42,10 @@ data: # Delimeters allowed for use: # https://grafana.com/docs/mimir/latest/configure/about-tenant-ids/ prefix: "" + # If true will use the tenant ID of the inbound request as the prefix of the new tenant id. + # Will be automatically suffixed with a `-` character. + # https://grafana.com/docs/mimir/latest/configure/about-tenant-ids/ + prefix_prefer_source: false # Whether to remove the tenant label from the request label_remove: false # To which header to add the tenant ID diff --git a/processor.go b/processor.go index 591b516..aaf1cfd 100644 --- a/processor.go +++ b/processor.go @@ -169,6 +169,14 @@ func (p *processor) handle(ctx *fh.RequestCtx) { return } + tenantPrefix := p.cfg.Tenant.Prefix + + if p.cfg.Tenant.PrefixPreferSource { + if string(ctx.Request.Header.Peek("X-Scope-OrgID")) != "" { + tenantPrefix = string(ctx.Request.Header.Peek("X-Scope-OrgID")) + "-" + } + } + clientIP := ctx.RemoteAddr() reqID, _ := uuid.NewRandom() @@ -176,7 +184,7 @@ func (p *processor) handle(ctx *fh.RequestCtx) { // If there's metadata - just accept the request and drop it if len(wrReqIn.Metadata) > 0 { if p.cfg.Metadata && p.cfg.Tenant.Default != "" { - r := p.send(clientIP, reqID, p.cfg.Tenant.Default, wrReqIn) + r := p.send(clientIP, reqID, tenantPrefix, p.cfg.Tenant.Default, wrReqIn) if r.err != nil { ctx.Error(err.Error(), fh.StatusInternalServerError) p.Errorf("src=%s req_id=%s: unable to proxy metadata: %s", clientIP, reqID, r.err) @@ -201,7 +209,7 @@ func (p *processor) handle(ctx *fh.RequestCtx) { metricTenant := "" var errs *me.Error - results := p.dispatch(clientIP, reqID, m) + results := p.dispatch(clientIP, reqID, tenantPrefix, m) code, body := 0, []byte("Ok") @@ -303,7 +311,7 @@ func (p *processor) marshal(wr *prompb.WriteRequest) (bufOut []byte, err error) return snappy.Encode(nil, b), nil } -func (p *processor) dispatch(clientIP net.Addr, reqID uuid.UUID, m map[string]*prompb.WriteRequest) (res []result) { +func (p *processor) dispatch(clientIP net.Addr, reqID uuid.UUID, tenantPrefix string, m map[string]*prompb.WriteRequest) (res []result) { var wg sync.WaitGroup res = make([]result, len(m)) @@ -314,7 +322,7 @@ func (p *processor) dispatch(clientIP net.Addr, reqID uuid.UUID, m map[string]*p go func(idx int, tenant string, wrReq *prompb.WriteRequest) { defer wg.Done() - r := p.send(clientIP, reqID, tenant, wrReq) + r := p.send(clientIP, reqID, tenantPrefix, tenant, wrReq) res[idx] = r }(i, tenant, wrReq) @@ -356,7 +364,7 @@ func (p *processor) processTimeseries(ts *prompb.TimeSeries) (tenant string, err return } -func (p *processor) send(clientIP net.Addr, reqID uuid.UUID, tenant string, wr *prompb.WriteRequest) (r result) { +func (p *processor) send(clientIP net.Addr, reqID uuid.UUID, tenantPrefix string, tenant string, wr *prompb.WriteRequest) (r result) { start := time.Now() r.tenant = tenant @@ -374,7 +382,7 @@ func (p *processor) send(clientIP net.Addr, reqID uuid.UUID, tenant string, wr * return } - p.fillRequestHeaders(clientIP, reqID, tenant, req) + p.fillRequestHeaders(clientIP, reqID, tenantPrefix, tenant, req) if p.auth.egressHeader != nil { req.Header.SetBytesV("Authorization", p.auth.egressHeader) @@ -398,14 +406,14 @@ func (p *processor) send(clientIP net.Addr, reqID uuid.UUID, tenant string, wr * } func (p *processor) fillRequestHeaders( - clientIP net.Addr, reqID uuid.UUID, tenant string, req *fh.Request) { + clientIP net.Addr, reqID uuid.UUID, tenantPrefix string, tenant string, req *fh.Request) { req.Header.Set("Content-Encoding", "snappy") req.Header.Set("Content-Type", "application/x-protobuf") req.Header.Set("X-Prometheus-Remote-Write-Version", "0.1.0") req.Header.Set("X-Cortex-Tenant-Client", clientIP.String()) req.Header.Set("X-Cortex-Tenant-ReqID", reqID.String()) - if p.cfg.Tenant.Prefix != "" { - tenant = p.cfg.Tenant.Prefix + tenant + if tenantPrefix != "" { + tenant = tenantPrefix + tenant } req.Header.Set(p.cfg.Tenant.Header, tenant) } diff --git a/processor_test.go b/processor_test.go index 7da5418..f97dc4c 100644 --- a/processor_test.go +++ b/processor_test.go @@ -219,7 +219,7 @@ func Test_request_headers(t *testing.T) { req := fh.AcquireRequest() clientIP, _ := net.ResolveIPAddr("ip", "1.1.1.1") reqID, _ := uuid.NewRandom() - p.fillRequestHeaders(clientIP, reqID, "my-tenant", req) + p.fillRequestHeaders(clientIP, reqID, "", "my-tenant", req) assert.Equal(t, "snappy", string(req.Header.Peek("Content-Encoding"))) assert.Equal(t, "my-tenant", string(req.Header.Peek("X-Scope-OrgID"))) @@ -234,7 +234,7 @@ func Test_request_headers_with_prefix(t *testing.T) { req := fh.AcquireRequest() clientIP, _ := net.ResolveIPAddr("ip", "1.1.1.1") reqID, _ := uuid.NewRandom() - p.fillRequestHeaders(clientIP, reqID, "my-tenant", req) + p.fillRequestHeaders(clientIP, reqID, "foobar-", "my-tenant", req) assert.Equal(t, "foobar-my-tenant", string(req.Header.Peek("X-Scope-OrgID"))) }