From 37bab2905b72904afe2cbe48b5354fc40d0357a4 Mon Sep 17 00:00:00 2001 From: dmitryk-dk Date: Fri, 20 Dec 2024 12:30:10 +0100 Subject: [PATCH 1/3] issue-85: enable custom headers for every requests --- pkg/plugin/datasource.go | 42 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/pkg/plugin/datasource.go b/pkg/plugin/datasource.go index 06f23ef5..e8d84ef1 100644 --- a/pkg/plugin/datasource.go +++ b/pkg/plugin/datasource.go @@ -25,7 +25,11 @@ var ( ) const ( - health = "/health" + health = "/health" + settingsHttpMethod = "httpMethod" + settingsCustomQueryParameters = "customQueryParameters" + httpHeaderName = "httpHeaderName" + httpHeaderValue = "httpHeaderValue" ) // NewDatasource creates a new datasource instance. @@ -47,6 +51,10 @@ func NewDatasource(ctx context.Context, settings backend.DataSourceInstanceSetti }, nil } +// Settings contains the raw DataSourceConfig as JSON as stored by Grafana server. +// It repeats the properties in this object and includes custom properties. +type Settings map[string]string + // Datasource is an example datasource which can respond to data queries, reports // its health and has streaming skills. type Datasource struct { @@ -173,33 +181,45 @@ func (d *Datasource) getQueryFromRaw(data json.RawMessage) (*Query, error) { // datasourceQuery process the query to the datasource and returns the result. func (d *Datasource) datasourceQuery(ctx context.Context, q *Query, isStream bool) (io.ReadCloser, error) { - var settings struct { - HTTPMethod string `json:"httpMethod"` - QueryParams string `json:"customQueryParameters"` - } + settings := make(Settings) if err := json.Unmarshal(d.settings.JSONData, &settings); err != nil { return nil, fmt.Errorf("failed to parse datasource settings: %w", err) } - if settings.HTTPMethod == "" { - settings.HTTPMethod = http.MethodPost + + httpMethod := settings[settingsHttpMethod] + if httpMethod == "" { + httpMethod = http.MethodPost } - reqURL, err := q.getQueryURL(d.settings.URL, settings.QueryParams) + customQueryParameters := settings[settingsCustomQueryParameters] + + reqURL, err := q.getQueryURL(d.settings.URL, customQueryParameters) if err != nil { return nil, fmt.Errorf("failed to create request URL: %w", err) } if isStream { - reqURL, err = q.queryTailURL(d.settings.URL, settings.QueryParams) + reqURL, err = q.queryTailURL(d.settings.URL, customQueryParameters) if err != nil { return nil, fmt.Errorf("failed to create request URL: %w", err) } } - req, err := http.NewRequestWithContext(ctx, settings.HTTPMethod, reqURL, nil) + req, err := http.NewRequestWithContext(ctx, httpMethod, reqURL, nil) if err != nil { return nil, fmt.Errorf("failed to create new request with context: %w", err) } + + for k, v := range settings { + if strings.HasPrefix(k, httpHeaderName) { + headerName := v + headerValueName := strings.Replace(k, httpHeaderName, httpHeaderValue, 1) + if headerValue, ok := d.settings.DecryptedSecureJSONData[headerValueName]; ok { + req.Header.Add(headerName, headerValue) + } + } + } + resp, err := d.httpClient.Do(req) if err != nil { if !isTrivialError(err) { @@ -209,7 +229,7 @@ func (d *Datasource) datasourceQuery(ctx context.Context, q *Query, isStream boo // Something in the middle between client and datasource might be closing // the connection. So we do a one more attempt in hope request will succeed. - req, err = http.NewRequestWithContext(ctx, settings.HTTPMethod, reqURL, nil) + req, err = http.NewRequestWithContext(ctx, httpMethod, reqURL, nil) if err != nil { return nil, fmt.Errorf("failed to create new request with context: %w", err) } From 29a0e7b749849190592023ba9a0ae6bce2653f59 Mon Sep 17 00:00:00 2001 From: dmitryk-dk Date: Fri, 20 Dec 2024 12:37:35 +0100 Subject: [PATCH 2/3] issue-85: add CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d94c27e..a3d15129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * SECURITY: bump golang.org/x/net to 0.33.0. See https://github.com/advisories/GHSA-w32m-9786-jp63 +* FEATURE: enable to set headers for every request to the datasource. It helps to use custom headers in the Grafana to define AccountID and ProjectID if it is needed. See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/85). + ## v0.13.1 * FEATURE: update plugin dependencies to satisfy Grafana marketplace requirements. From cb2ba26ec858454f27946e5a684ba3b71925c69d Mon Sep 17 00:00:00 2001 From: dmitryk-dk Date: Fri, 20 Dec 2024 12:40:11 +0100 Subject: [PATCH 3/3] issue-85: make linter happy --- pkg/plugin/datasource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/plugin/datasource.go b/pkg/plugin/datasource.go index e8d84ef1..5c1d20a5 100644 --- a/pkg/plugin/datasource.go +++ b/pkg/plugin/datasource.go @@ -26,7 +26,7 @@ var ( const ( health = "/health" - settingsHttpMethod = "httpMethod" + settingsHTTPMethod = "httpMethod" settingsCustomQueryParameters = "customQueryParameters" httpHeaderName = "httpHeaderName" httpHeaderValue = "httpHeaderValue" @@ -186,7 +186,7 @@ func (d *Datasource) datasourceQuery(ctx context.Context, q *Query, isStream boo return nil, fmt.Errorf("failed to parse datasource settings: %w", err) } - httpMethod := settings[settingsHttpMethod] + httpMethod := settings[settingsHTTPMethod] if httpMethod == "" { httpMethod = http.MethodPost }