| 
									
										
										
										
											2016-09-21 07:01:53 +02:00
										 |  |  | package prometheus | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-10-03 09:38:03 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-11-26 13:38:36 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-09-21 13:30:41 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-10-24 14:53:11 -05:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2022-01-04 07:22:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" | 
					
						
							| 
									
										
										
										
											2023-01-30 09:38:51 +01:00
										 |  |  | 	"github.com/patrickmn/go-cache" | 
					
						
							|  |  |  | 	apiv1 "github.com/prometheus/client_golang/api/prometheus/v1" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 23:53:41 +02:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/httpclient" | 
					
						
							| 
									
										
										
										
											2019-05-13 14:45:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2022-01-20 11:10:12 +01:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2022-04-01 04:26:49 -07:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2022-11-07 21:20:00 +03:00
										 |  |  | 	"github.com/grafana/grafana/pkg/tsdb/prometheus/client" | 
					
						
							| 
									
										
										
										
											2022-05-13 14:28:54 -04:00
										 |  |  | 	"github.com/grafana/grafana/pkg/tsdb/prometheus/querydata" | 
					
						
							| 
									
										
										
										
											2022-06-03 15:56:13 -03:00
										 |  |  | 	"github.com/grafana/grafana/pkg/tsdb/prometheus/resource" | 
					
						
							| 
									
										
										
										
											2021-10-15 13:37:27 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | var plog = log.New("tsdb.prometheus") | 
					
						
							| 
									
										
										
										
											2021-05-12 19:30:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | type Service struct { | 
					
						
							| 
									
										
										
										
											2022-05-13 14:28:54 -04:00
										 |  |  | 	im       instancemgmt.InstanceManager | 
					
						
							|  |  |  | 	features featuremgmt.FeatureToggles | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type instance struct { | 
					
						
							| 
									
										
										
										
											2022-10-24 14:53:11 -05:00
										 |  |  | 	queryData    *querydata.QueryData | 
					
						
							|  |  |  | 	resource     *resource.Resource | 
					
						
							|  |  |  | 	versionCache *cache.Cache | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-01 04:26:49 -07:00
										 |  |  | func ProvideService(httpClientProvider httpclient.Provider, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tracer tracing.Tracer) *Service { | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 	plog.Debug("initializing") | 
					
						
							| 
									
										
										
										
											2022-01-20 18:16:22 +01:00
										 |  |  | 	return &Service{ | 
					
						
							| 
									
										
										
										
											2022-05-13 14:28:54 -04:00
										 |  |  | 		im:       datasource.NewInstanceManager(newInstanceSettings(httpClientProvider, cfg, features, tracer)), | 
					
						
							|  |  |  | 		features: features, | 
					
						
							| 
									
										
										
										
											2021-08-25 15:11:22 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-06 16:22:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | func newInstanceSettings(httpClientProvider httpclient.Provider, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tracer tracing.Tracer) datasource.InstanceFactoryFunc { | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 	return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { | 
					
						
							| 
									
										
										
										
											2022-12-12 20:05:55 +03:00
										 |  |  | 		// Creates a http roundTripper. | 
					
						
							| 
									
										
										
										
											2022-11-03 21:44:37 +03:00
										 |  |  | 		opts, err := client.CreateTransportOptions(settings, cfg, plog) | 
					
						
							| 
									
										
										
										
											2021-05-27 12:43:21 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2022-06-23 14:48:16 +02:00
										 |  |  | 			return nil, fmt.Errorf("error creating transport options: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-04 11:18:45 +02:00
										 |  |  | 		httpClient, err := httpClientProvider.New(*opts) | 
					
						
							| 
									
										
										
										
											2022-06-23 14:48:16 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("error creating http client: %v", err) | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-13 14:28:54 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 11:18:45 +02:00
										 |  |  | 		// New version using custom client and better response parsing | 
					
						
							|  |  |  | 		qd, err := querydata.New(httpClient, features, tracer, settings, plog) | 
					
						
							| 
									
										
										
										
											2022-02-03 08:06:31 -08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 11:18:45 +02:00
										 |  |  | 		// Resource call management using new custom client same as querydata | 
					
						
							|  |  |  | 		r, err := resource.New(httpClient, settings, plog) | 
					
						
							| 
									
										
										
										
											2022-06-03 15:56:13 -03:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | 		return instance{ | 
					
						
							| 
									
										
										
										
											2022-10-24 14:53:11 -05:00
										 |  |  | 			queryData:    qd, | 
					
						
							|  |  |  | 			resource:     r, | 
					
						
							|  |  |  | 			versionCache: cache.New(time.Minute*1, time.Minute*5), | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | 		}, nil | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-19 23:53:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | 
					
						
							|  |  |  | 	if len(req.Queries) == 0 { | 
					
						
							|  |  |  | 		return &backend.QueryDataResponse{}, fmt.Errorf("query contains no queries") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | 	i, err := s.getInstance(req.PluginContext) | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-13 03:22:26 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 19:53:12 +03:00
										 |  |  | 	return i.queryData.Execute(ctx, req) | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-03 15:56:13 -03:00
										 |  |  | func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | 
					
						
							|  |  |  | 	i, err := s.getInstance(req.PluginContext) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-24 14:53:11 -05:00
										 |  |  | 	if strings.EqualFold(req.Path, "version-detect") { | 
					
						
							|  |  |  | 		versionObj, found := i.versionCache.Get("version") | 
					
						
							|  |  |  | 		if found { | 
					
						
							|  |  |  | 			return sender.Send(versionObj.(*backend.CallResourceResponse)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		vResp, err := i.resource.DetectVersion(ctx, req) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		i.versionCache.Set("version", vResp, cache.DefaultExpiration) | 
					
						
							|  |  |  | 		return sender.Send(vResp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 11:18:45 +02:00
										 |  |  | 	resp, err := i.resource.Execute(ctx, req) | 
					
						
							| 
									
										
										
										
											2022-06-03 15:56:13 -03:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-07-04 11:18:45 +02:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-06-03 15:56:13 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 11:18:45 +02:00
										 |  |  | 	return sender.Send(resp) | 
					
						
							| 
									
										
										
										
											2022-06-03 15:56:13 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | func (s *Service) getInstance(pluginCtx backend.PluginContext) (*instance, error) { | 
					
						
							| 
									
										
										
										
											2021-08-09 12:11:19 +03:00
										 |  |  | 	i, err := s.im.Get(pluginCtx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-12 05:34:09 -04:00
										 |  |  | 	in := i.(instance) | 
					
						
							|  |  |  | 	return &in, nil | 
					
						
							| 
									
										
										
										
											2016-09-21 07:01:53 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 12:05:49 +01:00
										 |  |  | // IsAPIError returns whether err is or wraps a Prometheus error. | 
					
						
							| 
									
										
										
										
											2020-11-26 13:38:36 +01:00
										 |  |  | func IsAPIError(err error) bool { | 
					
						
							| 
									
										
										
										
											2020-11-27 12:05:49 +01:00
										 |  |  | 	// Check if the right error type is in err's chain. | 
					
						
							| 
									
										
										
										
											2020-11-26 13:38:36 +01:00
										 |  |  | 	var e *apiv1.Error | 
					
						
							|  |  |  | 	return errors.As(err, &e) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func ConvertAPIError(err error) error { | 
					
						
							|  |  |  | 	var e *apiv1.Error | 
					
						
							|  |  |  | 	if errors.As(err, &e) { | 
					
						
							|  |  |  | 		return fmt.Errorf("%s: %s", e.Msg, e.Detail) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } |