func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapshotCommand) { if cmd.External { // external snapshot ref requires key and delete key if cmd.Key == "" || cmd.DeleteKey == "" { c.JsonApiErr(400, "Missing key and delete key for external snapshot", nil) return } cmd.OrgId = -1 cmd.UserId = -1 metrics.M_Api_Dashboard_Snapshot_External.Inc(1) } else { cmd.Key = util.GetRandomString(32) cmd.DeleteKey = util.GetRandomString(32) cmd.OrgId = c.OrgId cmd.UserId = c.UserId metrics.M_Api_Dashboard_Snapshot_Create.Inc(1) } if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to create snaphost", err) return } c.JSON(200, util.DynMap{ "key": cmd.Key, "deleteKey": cmd.DeleteKey, "url": setting.ToAbsUrl("dashboard/snapshot/" + cmd.Key), "deleteUrl": setting.ToAbsUrl("api/snapshots-delete/" + cmd.DeleteKey), }) }
func GraphiteProxy(c *middleware.Context) { proxyPath := c.Params("*") target, _ := url.Parse(setting.GraphiteUrl) // check if this is a special raintank_db requests if proxyPath == "metrics/find" { query := c.Query("query") if strings.HasPrefix(query, "raintank_db") { response, err := executeRaintankDbQuery(query, c.OrgId) if err != nil { c.JsonApiErr(500, "Failed to execute raintank_db query", err) return } c.JSON(200, response) return } } director := func(req *http.Request) { req.URL.Scheme = target.Scheme req.URL.Host = target.Host req.Header.Add("X-Org-Id", strconv.FormatInt(c.OrgId, 10)) req.URL.Path = util.JoinUrlFragments(target.Path, proxyPath) } proxy := &httputil.ReverseProxy{Director: director} proxy.ServeHTTP(c.RW(), c.Req.Request) }
func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) { userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.User} err := bus.Dispatch(&userQuery) if err != nil { c.JsonApiErr(401, "Invalid username or password", err) return } user := userQuery.Result passwordHashed := util.EncodePassword(cmd.Password, user.Salt) if passwordHashed != user.Password { c.JsonApiErr(401, "Invalid username or password", err) return } loginUserWithUser(user, c) result := map[string]interface{}{ "message": "Logged in", } if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 { result["redirectUrl"] = redirectTo c.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/") } metrics.M_Api_Login_Post.Inc(1) c.JSON(200, result) }
func handleListMetrics(req *cwRequest, c *middleware.Context) { creds := credentials.NewChainCredentials( []credentials.Provider{ &credentials.EnvProvider{}, &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database}, &ec2rolecreds.EC2RoleProvider{ExpiryWindow: 5 * time.Minute}, }) svc := cloudwatch.New(&aws.Config{ Region: aws.String(req.Region), Credentials: creds, }) reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` MetricName string `json:"metricName"` Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &cloudwatch.ListMetricsInput{ Namespace: aws.String(reqParam.Parameters.Namespace), MetricName: aws.String(reqParam.Parameters.MetricName), Dimensions: reqParam.Parameters.Dimensions, } resp, err := svc.ListMetrics(params) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func GetDataSourceById(c *middleware.Context) { query := m.GetDataSourceByIdQuery{ Id: c.ParamsInt64(":id"), OrgId: c.OrgId, } if err := bus.Dispatch(&query); err != nil { c.JsonApiErr(500, "Failed to query datasources", err) return } ds := query.Result c.JSON(200, &dtos.DataSource{ Id: ds.Id, OrgId: ds.OrgId, Name: ds.Name, Url: ds.Url, Type: ds.Type, Access: ds.Access, Password: ds.Password, Database: ds.Database, User: ds.User, BasicAuth: ds.BasicAuth, BasicAuthUser: ds.BasicAuthUser, BasicAuthPassword: ds.BasicAuthPassword, IsDefault: ds.IsDefault, JsonData: ds.JsonData, }) }
//ProxyDataSourceRequest TODO need to cache datasources func ProxyDataSourceRequest(c *middleware.Context) { id := c.ParamsInt64(":id") query := m.GetDataSourceByIdQuery{Id: id, OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { c.JsonApiErr(500, "Unable to load datasource meta data", err) return } ds := query.Result targetUrl, _ := url.Parse(ds.Url) if len(setting.DataProxyWhiteList) > 0 { if _, exists := setting.DataProxyWhiteList[targetUrl.Host]; !exists { c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil) return } } if query.Result.Type == m.DS_CLOUDWATCH { cloudwatch.HandleRequest(c) } else { proxyPath := c.Params("*") proxy := NewReverseProxy(&ds, proxyPath, targetUrl) proxy.Transport = dataProxyTransport proxy.ServeHTTP(c.RW(), c.Req.Request) } }
func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) { cmd.OrgId = c.OrgId err := bus.Dispatch(&cmd) if err != nil { if err == m.ErrDashboardWithSameNameExists { c.JSON(412, util.DynMap{"status": "name-exists", "message": err.Error()}) return } if err == m.ErrDashboardVersionMismatch { c.JSON(412, util.DynMap{"status": "version-mismatch", "message": err.Error()}) return } if err == m.ErrDashboardNotFound { c.JSON(404, util.DynMap{"status": "not-found", "message": err.Error()}) return } c.JsonApiErr(500, "Failed to save dashboard", err) return } metrics.M_Api_Dashboard_Post.Inc(1) c.JSON(200, util.DynMap{"status": "success", "slug": cmd.Result.Slug, "version": cmd.Result.Version}) }
func handleGetMetrics(req *cwRequest, c *middleware.Context) { reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) var namespaceMetrics []string if !isCustomMetrics(reqParam.Parameters.Namespace) { var exists bool if namespaceMetrics, exists = metricsMap[reqParam.Parameters.Namespace]; !exists { c.JsonApiErr(404, "Unable to find namespace "+reqParam.Parameters.Namespace, nil) return } } else { var err error cwData := req.GetDatasourceInfo() cwData.Namespace = reqParam.Parameters.Namespace if namespaceMetrics, err = getMetricsForCustomMetrics(cwData, getAllMetrics); err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } } sort.Sort(sort.StringSlice(namespaceMetrics)) result := []interface{}{} for _, name := range namespaceMetrics { result = append(result, util.DynMap{"text": name, "value": name}) } c.JSON(200, result) }
func handleListMetrics(req *cwRequest, c *middleware.Context) { cfg := getAwsConfig(req) svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` MetricName string `json:"metricName"` Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &cloudwatch.ListMetricsInput{ Namespace: aws.String(reqParam.Parameters.Namespace), MetricName: aws.String(reqParam.Parameters.MetricName), Dimensions: reqParam.Parameters.Dimensions, } var resp cloudwatch.ListMetricsOutput err := svc.ListMetricsPages(params, func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { metrics, _ := awsutil.ValuesAtPath(page, "Metrics") for _, metric := range metrics { resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric)) } return !lastPage }) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) { cfg := &aws.Config{ Region: aws.String(req.Region), Credentials: getCredentials(req.DataSource.Database), } svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { Parameters struct { AlarmName string `json:"alarmName"` HistoryItemType string `json:"historyItemType"` StartDate int64 `json:"startDate"` EndDate int64 `json:"endDate"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &cloudwatch.DescribeAlarmHistoryInput{ AlarmName: aws.String(reqParam.Parameters.AlarmName), StartDate: aws.Time(time.Unix(reqParam.Parameters.StartDate, 0)), EndDate: aws.Time(time.Unix(reqParam.Parameters.EndDate, 0)), } if reqParam.Parameters.HistoryItemType != "" { params.HistoryItemType = aws.String(reqParam.Parameters.HistoryItemType) } resp, err := svc.DescribeAlarmHistory(params) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) { cfg := getAwsConfig(req) svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` MetricName string `json:"metricName"` Dimensions []*cloudwatch.Dimension `json:"dimensions"` Statistic string `json:"statistic"` Period int64 `json:"period"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &cloudwatch.DescribeAlarmsForMetricInput{ Namespace: aws.String(reqParam.Parameters.Namespace), MetricName: aws.String(reqParam.Parameters.MetricName), Period: aws.Int64(reqParam.Parameters.Period), } if len(reqParam.Parameters.Dimensions) != 0 { params.Dimensions = reqParam.Parameters.Dimensions } if reqParam.Parameters.Statistic != "" { params.Statistic = aws.String(reqParam.Parameters.Statistic) } resp, err := svc.DescribeAlarmsForMetric(params) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func ValidateOrgPlaylist(c *middleware.Context) { id := c.ParamsInt64(":id") query := m.GetPlaylistByIdQuery{Id: id} err := bus.Dispatch(&query) if err != nil { c.JsonApiErr(404, "Playlist not found", err) return } if query.Result.OrgId == 0 { c.JsonApiErr(404, "Playlist not found", err) return } if query.Result.OrgId != c.OrgId { c.JsonApiErr(403, "You are not allowed to edit/view playlist", nil) return } items, itemsErr := LoadPlaylistItemDTOs(id) if itemsErr != nil { c.JsonApiErr(404, "Playlist items not found", err) return } if len(items) == 0 { c.JsonApiErr(404, "Playlist is empty", itemsErr) return } }
func ProxyDataSourceRequest(c *middleware.Context) { c.TimeRequest(metrics.M_DataSource_ProxyReq_Timer) ds, err := getDatasource(c.ParamsInt64(":id"), c.OrgId) if err != nil { c.JsonApiErr(500, "Unable to load datasource meta data", err) return } targetUrl, _ := url.Parse(ds.Url) if len(setting.DataProxyWhiteList) > 0 { if _, exists := setting.DataProxyWhiteList[targetUrl.Host]; !exists { c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil) return } } if ds.Type == m.DS_CLOUDWATCH { cloudwatch.HandleRequest(c, ds) } else { proxyPath := c.Params("*") proxy := NewReverseProxy(ds, proxyPath, targetUrl) proxy.Transport = dataProxyTransport proxy.ServeHTTP(c.Resp, c.Req.Request) c.Resp.Header().Del("Set-Cookie") } }
func handleGetDimensions(req *cwRequest, c *middleware.Context) { reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) var dimensionValues []string if !isCustomMetrics(reqParam.Parameters.Namespace) { var exists bool if dimensionValues, exists = dimensionsMap[reqParam.Parameters.Namespace]; !exists { c.JsonApiErr(404, "Unable to find dimension "+reqParam.Parameters.Namespace, nil) return } } else { var err error if dimensionValues, err = getDimensionsForCustomMetrics(req.Region, reqParam.Parameters.Namespace, req.DataSource.Database, getAllMetrics); err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } } sort.Sort(sort.StringSlice(dimensionValues)) result := []interface{}{} for _, name := range dimensionValues { result = append(result, util.DynMap{"text": name, "value": name}) } c.JSON(200, result) }
func handleListMetrics(req *cwRequest, c *middleware.Context) { svc := cloudwatch.New(&aws.Config{Region: aws.String(req.Region)}) reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` MetricName string `json:"metricName"` Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &cloudwatch.ListMetricsInput{ Namespace: aws.String(reqParam.Parameters.Namespace), MetricName: aws.String(reqParam.Parameters.MetricName), Dimensions: reqParam.Parameters.Dimensions, } resp, err := svc.ListMetrics(params) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func handleDescribeInstances(req *cwRequest, c *middleware.Context) { svc := ec2.New(&aws.Config{Region: aws.String(req.Region)}) reqParam := &struct { Parameters struct { Filters []*ec2.Filter `json:"filters"` InstanceIds []*string `json:"instanceIds"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &ec2.DescribeInstancesInput{} if len(reqParam.Parameters.Filters) > 0 { params.Filters = reqParam.Parameters.Filters } if len(reqParam.Parameters.InstanceIds) > 0 { params.InstanceIds = reqParam.Parameters.InstanceIds } resp, err := svc.DescribeInstances(params) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) { svc := cloudwatch.New(&aws.Config{Region: aws.String(req.Region)}) reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` MetricName string `json:"metricName"` Dimensions []*cloudwatch.Dimension `json:"dimensions"` Statistics []*string `json:"statistics"` StartTime int64 `json:"startTime"` EndTime int64 `json:"endTime"` Period int64 `json:"period"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) params := &cloudwatch.GetMetricStatisticsInput{ Namespace: aws.String(reqParam.Parameters.Namespace), MetricName: aws.String(reqParam.Parameters.MetricName), Dimensions: reqParam.Parameters.Dimensions, Statistics: reqParam.Parameters.Statistics, StartTime: aws.Time(time.Unix(reqParam.Parameters.StartTime, 0)), EndTime: aws.Time(time.Unix(reqParam.Parameters.EndTime, 0)), Period: aws.Int64(reqParam.Parameters.Period), } resp, err := svc.GetMetricStatistics(params) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func Search(c *middleware.Context) { query := c.Query("query") tags := c.QueryStrings("tag") starred := c.Query("starred") limit := c.QueryInt("limit") if limit == 0 { limit = 1000 } searchQuery := search.Query{ Title: query, Tags: tags, UserId: c.UserId, Limit: limit, IsStarred: starred == "true", OrgId: c.OrgId, } err := bus.Dispatch(&searchQuery) if err != nil { c.JsonApiErr(500, "Search failed", err) return } c.JSON(200, searchQuery.Result) }
func HandleRequest(c *middleware.Context, ds *m.DataSource) { var req sqlDataRequest req.Body, _ = ioutil.ReadAll(c.Req.Request.Body) json.Unmarshal(req.Body, &req) log.Debug("SQL request: query='%v'", req.Query) engine, err := getEngine(ds) if err != nil { c.JsonApiErr(500, "Unable to open SQL connection", err) return } defer engine.Close() session := engine.NewSession() defer session.Close() db := session.DB() result, err := getData(db, &req) if err != nil { c.JsonApiErr(500, fmt.Sprintf("Data error: %v, Query: %s", err.Error(), req.Query), err) return } c.JSON(200, result) }
func GetDataSources(c *middleware.Context) { query := m.GetDataSourcesQuery{OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { c.JsonApiErr(500, "Failed to query datasources", err) return } result := make([]*dtos.DataSource, len(query.Result)) for i, ds := range query.Result { result[i] = &dtos.DataSource{ Id: ds.Id, OrgId: ds.OrgId, Name: ds.Name, Url: ds.Url, Type: ds.Type, Access: ds.Access, Password: ds.Password, Database: ds.Database, User: ds.User, BasicAuth: ds.BasicAuth, IsDefault: ds.IsDefault, } } c.JSON(200, result) }
func GetDashboard(c *middleware.Context) { metrics.M_Api_Dashboard_Get.Inc(1) slug := strings.ToLower(c.Params(":slug")) query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId} err := bus.Dispatch(&query) if err != nil { c.JsonApiErr(404, "Dashboard not found", nil) return } isStarred, err := isDasboardStarredByUser(c, query.Result.Id) if err != nil { c.JsonApiErr(500, "Error while checking if dashboard was starred by user", err) return } dash := query.Result dto := dtos.DashboardFullWithMeta{ Dashboard: dash.Data, Meta: dtos.DashboardMeta{ IsStarred: isStarred, Slug: slug, Type: m.DashTypeDB, CanStar: c.IsSignedIn, CanSave: c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR, CanEdit: canEditDashboard(c.OrgRole), }, } c.JSON(200, dto) }
func GetDashboardSnapshot(c *middleware.Context) { key := c.Params(":key") query := &m.GetDashboardSnapshotQuery{Key: key} err := bus.Dispatch(query) if err != nil { c.JsonApiErr(500, "Failed to get dashboard snapshot", err) return } snapshot := query.Result // expired snapshots should also be removed from db if snapshot.Expires.Before(time.Now()) { c.JsonApiErr(404, "Snapshot not found", err) return } dto := dtos.DashboardFullWithMeta{ Dashboard: snapshot.Dashboard, Meta: dtos.DashboardMeta{ Type: m.DashTypeSnapshot, IsSnapshot: true, Created: snapshot.Created, Expires: snapshot.Expires, }, } metrics.M_Api_Dashboard_Snapshot_Get.Inc(1) c.Resp.Header().Set("Cache-Control", "public, max-age=3600") c.JSON(200, dto) }
func LoginApiPing(c *middleware.Context) { if !tryLoginUsingRememberCookie(c) { c.JsonApiErr(401, "Unauthorized", nil) return } c.JsonOK("Logged in") }
func AddAlert(c *middleware.Context, cmd m.AddAlertCommand) { cmd.OrgId = c.OrgId if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to add alert", err) return } c.JSON(200, cmd.Result) }
func GetAlerts(c *middleware.Context) { query := m.GetAlertsQuery{OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { c.JsonApiErr(500, "Failed to list alerts", err) return } c.JSON(200, query.Result) }
func GetFrontendSettings(c *middleware.Context) { settings, err := getFrontendSettingsMap(c) if err != nil { c.JsonApiErr(400, "Failed to get frontend settings", err) return } c.JSON(200, settings) }
func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) { cmd.OrgId = c.OrgId if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to add datasource", err) return } c.JSON(200, util.DynMap{"message": "Datasource added", "id": cmd.Result.Id}) }
func GetDashboardTags(c *middleware.Context) { query := m.GetDashboardTagsQuery{OrgId: c.OrgId} err := bus.Dispatch(&query) if err != nil { c.JsonApiErr(500, "Failed to get tags from database", err) return } c.JSON(200, query.Result) }
func DeleteDashboardSnapshot(c *middleware.Context) { key := c.Params(":key") cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: key} if err := bus.Dispatch(cmd); err != nil { c.JsonApiErr(500, "Failed to delete dashboard snapshot", err) return } c.JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from a CDN cache."}) }
func AdminGetStats(c *middleware.Context) { statsQuery := m.GetAdminStatsQuery{} if err := bus.Dispatch(&statsQuery); err != nil { c.JsonApiErr(500, "Failed to get admin stats from database", err) return } c.JSON(200, statsQuery.Result) }