diff --git a/api/graphite.go b/api/graphite.go index 85b72a91c1..5eaa8cf7b3 100644 --- a/api/graphite.go +++ b/api/graphite.go @@ -1201,3 +1201,55 @@ func (s *Server) graphiteTagDelSeries(ctx *middleware.Context, request models.Gr response.Write(ctx, response.NewJson(200, res, "")) } + +// showPlan attempts to create a Plan given a /render target query. +// If the Plan creation is successful it returns 200, JSON marshaling of Plan. +// Otherwise, it returns 400, error details. +// This is needed to determine if a query cannot be resolved in localOnly mode. +func (s *Server) showPlan(ctx *middleware.Context, request models.GraphiteRender) { + // note: the model is already validated to assure at least one of them has len >0 + if len(request.Targets) == 0 { + request.Targets = request.TargetsRails + } + + now := time.Now() + defaultFrom := uint32(now.Add(-time.Duration(24) * time.Hour).Unix()) + defaultTo := uint32(now.Unix()) + fromUnix, toUnix, err := getFromTo(request.FromTo, now, defaultFrom, defaultTo) + if err != nil { + response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error())) + return + } + if fromUnix >= toUnix { + response.Write(ctx, response.NewError(http.StatusBadRequest, InvalidTimeRangeErr.Error())) + return + } + + // render API is modeled after graphite, so from exclusive, to inclusive. + // in MT, from is inclusive, to is exclusive (which is akin to slice syntax) + // so we must adjust + fromUnix += 1 + toUnix += 1 + + exprs, err := expr.ParseMany(request.Targets) + if err != nil { + response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error())) + return + } + + stable := request.Process == "stable" + mdp := request.MaxDataPoints + + plan, err := expr.NewPlan(exprs, fromUnix, toUnix, mdp, stable, nil) + if err != nil { + response.Write(ctx, response.NewError(http.StatusBadRequest, err.Error())) + return + } + switch request.Format { + case "json": + response.Write(ctx, response.NewJson(200, plan, "")) + default: + response.Write(ctx, response.NewError(http.StatusBadRequest, "Unsupported response format requested: "+request.Format)) + } + plan.Clean() +} diff --git a/api/routes.go b/api/routes.go index 1864d22e89..6d90ba8971 100644 --- a/api/routes.go +++ b/api/routes.go @@ -53,6 +53,8 @@ func (s *Server) RegisterRoutes() { ctx.Write(nil) }) + r.Combo("/showplan", cBody, withOrg, ready, bind(models.GraphiteRender{})).Get(s.showPlan).Post(s.showPlan) + // Graphite endpoints r.Combo("/render", cBody, withOrg, ready, bind(models.GraphiteRender{})).Get(s.renderMetrics).Post(s.renderMetrics) r.Combo("/metrics/find", withOrg, ready, bind(models.GraphiteFind{})).Get(s.metricsFind).Post(s.metricsFind)