Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue-85: enable custom headers for every requests #183

Merged
merged 3 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
42 changes: 31 additions & 11 deletions pkg/plugin/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ var (
)

const (
health = "/health"
health = "/health"
settingsHTTPMethod = "httpMethod"
settingsCustomQueryParameters = "customQueryParameters"
httpHeaderName = "httpHeaderName"
httpHeaderValue = "httpHeaderValue"
)

// NewDatasource creates a new datasource instance.
Expand All @@ -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 {
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
}
Expand Down
Loading