| 
									
										
										
										
											2015-01-06 16:11:00 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2023-09-11 18:13:13 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-07-24 18:34:56 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2022-07-13 21:27:03 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-02-04 03:47:45 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2016-06-03 21:06:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-31 23:35:03 +08:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							| 
									
										
										
										
											2022-05-18 02:52:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 21:06:57 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/dtos" | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/response" | 
					
						
							| 
									
										
										
										
											2024-02-01 02:36:51 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/routing" | 
					
						
							| 
									
										
										
										
											2024-06-20 22:53:07 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/apimachinery/identity" | 
					
						
							| 
									
										
										
										
											2023-09-11 18:13:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/middleware/requestmeta" | 
					
						
							| 
									
										
										
										
											2024-02-02 06:27:30 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | 	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/datasources" | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2024-06-13 12:11:35 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util/errhttp" | 
					
						
							| 
									
										
										
										
											2021-11-29 17:18:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							| 
									
										
										
										
											2015-01-06 16:11:00 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-29 18:08:40 +08:00
										 |  |  | func (hs *HTTPServer) handleQueryMetricsError(err error) *response.NormalResponse { | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 	if errors.Is(err, datasources.ErrDataSourceAccessDenied) { | 
					
						
							| 
									
										
										
										
											2022-04-29 18:08:40 +08:00
										 |  |  | 		return response.Error(http.StatusForbidden, "Access denied to data source", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 	if errors.Is(err, datasources.ErrDataSourceNotFound) { | 
					
						
							| 
									
										
										
										
											2022-04-29 18:08:40 +08:00
										 |  |  | 		return response.Error(http.StatusNotFound, "Data source not found", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-13 21:27:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-15 00:19:57 +08:00
										 |  |  | 	return response.ErrOrFallback(http.StatusInternalServerError, "Query data error", err) | 
					
						
							| 
									
										
										
										
											2022-04-29 18:08:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-01 02:36:51 +08:00
										 |  |  | // metrics.go
 | 
					
						
							|  |  |  | func (hs *HTTPServer) getDSQueryEndpoint() web.Handler { | 
					
						
							| 
									
										
										
										
											2024-04-19 17:26:21 +08:00
										 |  |  | 	if hs.Features.IsEnabledGlobally(featuremgmt.FlagQueryServiceRewrite) { | 
					
						
							| 
									
										
										
										
											2024-02-01 02:36:51 +08:00
										 |  |  | 		// rewrite requests from /ds/query to the new query service
 | 
					
						
							|  |  |  | 		namespaceMapper := request.GetNamespaceMapper(hs.Cfg) | 
					
						
							|  |  |  | 		return func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2024-06-20 22:53:07 +08:00
										 |  |  | 			user, err := identity.GetRequester(r.Context()) | 
					
						
							| 
									
										
										
										
											2024-02-01 02:36:51 +08:00
										 |  |  | 			if err != nil || user == nil { | 
					
						
							|  |  |  | 				errhttp.Write(r.Context(), fmt.Errorf("no user"), w) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-06-20 22:53:07 +08:00
										 |  |  | 			r.URL.Path = "/apis/query.grafana.app/v0alpha1/namespaces/" + namespaceMapper(user.GetOrgID()) + "/query" | 
					
						
							| 
									
										
										
										
											2024-02-01 02:36:51 +08:00
										 |  |  | 			hs.clientConfigProvider.DirectlyServeHTTP(w, r) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return routing.Wrap(hs.QueryMetricsV2) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-17 05:17:05 +08:00
										 |  |  | // QueryMetricsV2 returns query metrics.
 | 
					
						
							| 
									
										
										
										
											2022-07-27 21:54:37 +08:00
										 |  |  | // swagger:route POST /ds/query ds queryMetricsWithExpressions
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2022-09-12 15:40:35 +08:00
										 |  |  | // DataSource query metrics with expressions.
 | 
					
						
							| 
									
										
										
										
											2022-07-27 21:54:37 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // If you are running Grafana Enterprise and have Fine-grained access control enabled
 | 
					
						
							|  |  |  | // you need to have a permission with action: `datasources:query`.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: queryMetricsWithExpressionsRespons
 | 
					
						
							|  |  |  | // 207: queryMetricsWithExpressionsRespons
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 400: badRequestError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | func (hs *HTTPServer) QueryMetricsV2(c *contextmodel.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	reqDTO := dtos.MetricRequest{} | 
					
						
							|  |  |  | 	if err := web.Bind(c.Req, &reqDTO); err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusBadRequest, "bad request data", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 00:30:33 +08:00
										 |  |  | 	resp, err := hs.queryDataService.QueryData(c.Req.Context(), c.SignedInUser, c.SkipDSCache, reqDTO) | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return hs.handleQueryMetricsError(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-09-11 18:13:13 +08:00
										 |  |  | 	return hs.toJsonStreamingResponse(c.Req.Context(), resp) | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 18:13:13 +08:00
										 |  |  | func (hs *HTTPServer) toJsonStreamingResponse(ctx context.Context, qdr *backend.QueryDataResponse) response.Response { | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 	statusCode := http.StatusOK | 
					
						
							|  |  |  | 	for _, res := range qdr.Responses { | 
					
						
							|  |  |  | 		if res.Error != nil { | 
					
						
							| 
									
										
										
										
											2024-07-10 17:15:10 +08:00
										 |  |  | 			statusCode = http.StatusBadRequest | 
					
						
							|  |  |  | 			break | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-10 17:15:10 +08:00
										 |  |  | 	if statusCode == http.StatusBadRequest { | 
					
						
							| 
									
										
										
										
											2023-09-11 18:13:13 +08:00
										 |  |  | 		// an error in the response we treat as downstream.
 | 
					
						
							|  |  |  | 		requestmeta.WithDownstreamStatusSource(ctx) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 	return response.JSONStreaming(statusCode, qdr) | 
					
						
							| 
									
										
										
										
											2019-10-25 21:28:26 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-27 21:54:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // swagger:parameters queryMetricsWithExpressions
 | 
					
						
							|  |  |  | type QueryMetricsWithExpressionsBodyParams struct { | 
					
						
							|  |  |  | 	// in:body
 | 
					
						
							|  |  |  | 	// required:true
 | 
					
						
							|  |  |  | 	Body dtos.MetricRequest `json:"body"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:response queryMetricsWithExpressionsRespons
 | 
					
						
							|  |  |  | type QueryMetricsWithExpressionsRespons struct { | 
					
						
							|  |  |  | 	// The response message
 | 
					
						
							|  |  |  | 	// in: body
 | 
					
						
							|  |  |  | 	Body *backend.QueryDataResponse `json:"body"` | 
					
						
							|  |  |  | } |