mirror of https://github.com/grafana/grafana.git
				
				
				
			Plugins: Support headers field for check health (#49930)
This commit is contained in:
		
							parent
							
								
									a91ecc566b
								
							
						
					
					
						commit
						a7813275a5
					
				|  | @ -293,6 +293,17 @@ To allow Grafana to pass the access token to the plugin, update the data source | |||
| When configured, Grafana will pass the user's token to the plugin in an Authorization header, available on the `QueryDataRequest` object on the `QueryData` request in your backend data source. | ||||
| 
 | ||||
| ```go | ||||
| func (ds *dataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { | ||||
| 	token := strings.Fields(req.Headers["Authorization"]) | ||||
| 	var ( | ||||
| 		tokenType   = token[0] | ||||
| 		accessToken = token[1] | ||||
| 	) | ||||
| 
 | ||||
| 	// ... | ||||
| 	return &backend.CheckHealthResult{Status: backend.HealthStatusOk}, nil | ||||
| } | ||||
| 
 | ||||
| func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | ||||
|   token := strings.Fields(req.Headers["Authorization"]) | ||||
| 	var ( | ||||
|  | @ -309,6 +320,13 @@ func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataReque | |||
| In addition, if the user's token includes an ID token, Grafana will pass the user's ID token to the plugin in an `X-ID-Token` header, available on the `QueryDataRequest` object on the `QueryData` request in your backend data source. | ||||
| 
 | ||||
| ```go | ||||
| func (ds *dataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { | ||||
| 	idToken := req.Headers["X-ID-Token"] | ||||
| 
 | ||||
| 	// ... | ||||
| 	return &backend.CheckHealthResult{Status: backend.HealthStatusOk}, nil | ||||
| } | ||||
| 
 | ||||
| func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | ||||
|   idToken := req.Headers["X-ID-Token"] | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										2
									
								
								go.mod
								
								
								
								
							|  | @ -56,7 +56,7 @@ require ( | |||
| 	github.com/grafana/cuetsy v0.0.2 | ||||
| 	github.com/grafana/grafana-aws-sdk v0.10.3 | ||||
| 	github.com/grafana/grafana-azure-sdk-go v1.2.0 | ||||
| 	github.com/grafana/grafana-plugin-sdk-go v0.134.0 | ||||
| 	github.com/grafana/grafana-plugin-sdk-go v0.135.0 | ||||
| 	github.com/grafana/loki v1.6.2-0.20211015002020-7832783b1caa | ||||
| 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 | ||||
| 	github.com/hashicorp/go-hclog v1.0.0 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										4
									
								
								go.sum
								
								
								
								
							|  | @ -1461,8 +1461,8 @@ github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW3 | |||
| github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= | ||||
| github.com/grafana/grafana-plugin-sdk-go v0.125.0/go.mod h1:9YiJ5GUxIsIEUC0qR9+BJVP5M7mCSP6uc6Ne62YKkgc= | ||||
| github.com/grafana/grafana-plugin-sdk-go v0.129.0/go.mod h1:4edtosZepfQF9jkQwRywJsNSJzXTHmzbmcVcAl8MEQc= | ||||
| github.com/grafana/grafana-plugin-sdk-go v0.134.0 h1:8j8vsvhU3GabRPWB1EnFKSWt60yQVFPEE/5P1QV2gFw= | ||||
| github.com/grafana/grafana-plugin-sdk-go v0.134.0/go.mod h1:jmrxelOJKrIK0yrsIzcotS8pbqPZozbmJgGy7k3hK1k= | ||||
| github.com/grafana/grafana-plugin-sdk-go v0.135.0 h1:IQrwA/RCPr5IhE3lVxIpgEXwZohx7gp3rJ1KJa0KT5g= | ||||
| github.com/grafana/grafana-plugin-sdk-go v0.135.0/go.mod h1:jmrxelOJKrIK0yrsIzcotS8pbqPZozbmJgGy7k3hK1k= | ||||
| github.com/grafana/loki v1.6.2-0.20211015002020-7832783b1caa h1:+pXjAxavVR2FKKNsuuCXGCWEj8XGc1Af6SPiyBpzU2A= | ||||
| github.com/grafana/loki v1.6.2-0.20211015002020-7832783b1caa/go.mod h1:0O8o/juxNSKN/e+DzWDTRkl7Zm8CkZcz0NDqEdojlrk= | ||||
| github.com/grafana/saml v0.0.0-20211007135653-aed1b2edd86b h1:YiSGp34F4V0G08HHx1cJBf2GVgwYAkXQjzuVs1t8jYk= | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/services/datasources" | ||||
| 	"github.com/grafana/grafana/pkg/services/datasources/permissions" | ||||
| 	"github.com/grafana/grafana/pkg/util" | ||||
| 	"github.com/grafana/grafana/pkg/util/proxyutil" | ||||
| 	"github.com/grafana/grafana/pkg/web" | ||||
| ) | ||||
| 
 | ||||
|  | @ -568,6 +569,7 @@ func (hs *HTTPServer) checkDatasourceHealth(c *models.ReqContext, ds *models.Dat | |||
| 			PluginID:                   plugin.ID, | ||||
| 			DataSourceInstanceSettings: dsInstanceSettings, | ||||
| 		}, | ||||
| 		Headers: map[string]string{}, | ||||
| 	} | ||||
| 
 | ||||
| 	var dsURL string | ||||
|  | @ -580,6 +582,21 @@ func (hs *HTTPServer) checkDatasourceHealth(c *models.ReqContext, ds *models.Dat | |||
| 		return response.Error(http.StatusForbidden, "Access denied", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if hs.DataProxy.OAuthTokenService.IsOAuthPassThruEnabled(ds) { | ||||
| 		if token := hs.DataProxy.OAuthTokenService.GetCurrentOAuthToken(c.Req.Context(), c.SignedInUser); token != nil { | ||||
| 			req.Headers["Authorization"] = fmt.Sprintf("%s %s", token.Type(), token.AccessToken) | ||||
| 			idToken, ok := token.Extra("id_token").(string) | ||||
| 			if ok && idToken != "" { | ||||
| 				req.Headers["X-ID-Token"] = idToken | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	proxyutil.ClearCookieHeader(c.Req, ds.AllowedCookies()) | ||||
| 	if cookieStr := c.Req.Header.Get("Cookie"); cookieStr != "" { | ||||
| 		req.Headers["Cookie"] = cookieStr | ||||
| 	} | ||||
| 
 | ||||
| 	resp, err := hs.pluginClient.CheckHealth(c.Req.Context(), req) | ||||
| 	if err != nil { | ||||
| 		return translatePluginRequestErrorToAPIError(err) | ||||
|  |  | |||
|  | @ -222,14 +222,7 @@ func (proxy *DataSourceProxy) director(req *http.Request) { | |||
| 
 | ||||
| 	applyUserHeader(proxy.cfg.SendUserHeader, req, proxy.ctx.SignedInUser) | ||||
| 
 | ||||
| 	keepCookieNames := []string{} | ||||
| 	if proxy.ds.JsonData != nil { | ||||
| 		if keepCookies := proxy.ds.JsonData.Get("keepCookies"); keepCookies != nil { | ||||
| 			keepCookieNames = keepCookies.MustStringArray() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	proxyutil.ClearCookieHeader(req, keepCookieNames) | ||||
| 	proxyutil.ClearCookieHeader(req, proxy.ds.AllowedCookies()) | ||||
| 	req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion)) | ||||
| 
 | ||||
| 	jsonData := make(map[string]interface{}) | ||||
|  |  | |||
|  | @ -318,6 +318,7 @@ func (hs *HTTPServer) CheckHealth(c *models.ReqContext) response.Response { | |||
| 
 | ||||
| 	resp, err := hs.pluginClient.CheckHealth(c.Req.Context(), &backend.CheckHealthRequest{ | ||||
| 		PluginContext: pCtx, | ||||
| 		Headers:       map[string]string{}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return translatePluginRequestErrorToAPIError(err) | ||||
|  |  | |||
|  | @ -67,6 +67,18 @@ type DataSource struct { | |||
| 	Updated time.Time `json:"updated"` | ||||
| } | ||||
| 
 | ||||
| // AllowedCookies parses the jsondata.keepCookies and returns a list of
 | ||||
| // allowed cookies, otherwise an empty list.
 | ||||
| func (ds DataSource) AllowedCookies() []string { | ||||
| 	if ds.JsonData != nil { | ||||
| 		if keepCookies := ds.JsonData.Get("keepCookies"); keepCookies != nil { | ||||
| 			return keepCookies.MustStringArray() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return []string{} | ||||
| } | ||||
| 
 | ||||
| // ----------------------
 | ||||
| // COMMANDS
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -115,7 +115,7 @@ func (c *ClientV2) CheckHealth(ctx context.Context, req *backend.CheckHealthRequ | |||
| 	} | ||||
| 
 | ||||
| 	protoContext := backend.ToProto().PluginContext(req.PluginContext) | ||||
| 	protoResp, err := c.DiagnosticsClient.CheckHealth(ctx, &pluginv2.CheckHealthRequest{PluginContext: protoContext}) | ||||
| 	protoResp, err := c.DiagnosticsClient.CheckHealth(ctx, &pluginv2.CheckHealthRequest{PluginContext: protoContext, Headers: req.Headers}) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		if status.Code(err) == codes.Unimplemented { | ||||
|  |  | |||
|  | @ -151,14 +151,8 @@ func (s *Service) handleQueryData(ctx context.Context, user *models.SignedInUser | |||
| 		req.Headers[k] = v | ||||
| 	} | ||||
| 
 | ||||
| 	if parsedReq.httpRequest != nil && parsedReq.httpRequest.Header.Get("Cookie") != "" && ds.JsonData != nil { | ||||
| 		keepCookieNames := []string{} | ||||
| 
 | ||||
| 		if keepCookies := ds.JsonData.Get("keepCookies"); keepCookies != nil { | ||||
| 			keepCookieNames = keepCookies.MustStringArray() | ||||
| 		} | ||||
| 
 | ||||
| 		proxyutil.ClearCookieHeader(parsedReq.httpRequest, keepCookieNames) | ||||
| 	if parsedReq.httpRequest != nil { | ||||
| 		proxyutil.ClearCookieHeader(parsedReq.httpRequest, ds.AllowedCookies()) | ||||
| 		if cookieStr := parsedReq.httpRequest.Header.Get("Cookie"); cookieStr != "" { | ||||
| 			req.Headers["Cookie"] = cookieStr | ||||
| 		} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue