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 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 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), Created: dash.Created, Updated: dash.Updated, }, } 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, "Dashboard 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 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 LoginApiPing(c *middleware.Context) { if !tryLoginUsingRememberCookie(c) { c.JsonApiErr(401, "Unauthorized", nil) return } c.JsonOK("Logged in") }
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 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 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 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 UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) { cmd.OrgId = c.OrgId cmd.Id = c.ParamsInt64(":id") err := bus.Dispatch(&cmd) if err != nil { c.JsonApiErr(500, "Failed to update datasource", err) return } c.JsonOK("Datasource updated") }
func AdminDeleteUser(c *middleware.Context) { userId := c.ParamsInt64(":id") cmd := m.DeleteUserCommand{UserId: userId} if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to delete user", err) return } c.JsonOK("User deleted") }
func HandleRequest(c *middleware.Context, ds *m.DataSource) { var req cwRequest req.Body, _ = ioutil.ReadAll(c.Req.Request.Body) req.DataSource = ds json.Unmarshal(req.Body, &req) if handler, found := actionHandlers[req.Action]; !found { c.JsonApiErr(500, "Unexpected AWS Action", errors.New(req.Action)) return } else { handler(&req, c) } }
func NotFoundHandler(c *middleware.Context) { if c.IsApiRequest() { c.JsonApiErr(404, "Not found", nil) return } if err := setIndexViewData(c); err != nil { c.Handle(500, "Failed to get settings", err) return } c.HTML(404, "index") }
func AdminUpdateUserPermissions(c *middleware.Context, form dtos.AdminUpdateUserPermissionsForm) { userId := c.ParamsInt64(":id") cmd := m.UpdateUserPermissionsCommand{ UserId: userId, IsGrafanaAdmin: form.IsGrafanaAdmin, } if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to update user permissions", err) return } c.JsonOK("User permissions updated") }
func GetDashboardFromJsonFile(c *middleware.Context) { file := c.Params(":file") dashboard := search.GetDashboardFromJsonIndex(file) if dashboard == nil { c.JsonApiErr(404, "Dashboard not found", nil) return } dash := dtos.DashboardFullWithMeta{Dashboard: dashboard.Data} dash.Meta.Type = m.DashTypeJson dash.Meta.CanEdit = canEditDashboard(c.OrgRole) c.JSON(200, &dash) }
func handleDescribeInstances(req *cwRequest, c *middleware.Context) { sess := session.New() creds := credentials.NewChainCredentials( []credentials.Provider{ &credentials.EnvProvider{}, &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database}, &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute}, }) cfg := &aws.Config{ Region: aws.String(req.Region), Credentials: creds, } svc := ec2.New(session.New(cfg), cfg) 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 } var resp ec2.DescribeInstancesOutput err := svc.DescribeInstancesPages(params, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool { reservations, _ := awsutil.ValuesAtPath(page, "Reservations") for _, reservation := range reservations { resp.Reservations = append(resp.Reservations, reservation.(*ec2.Reservation)) } return !lastPage }) if err != nil { c.JsonApiErr(500, "Unable to call AWS API", err) return } c.JSON(200, resp) }
func handleListMetrics(req *cwRequest, c *middleware.Context) { sess := session.New() creds := credentials.NewChainCredentials( []credentials.Provider{ &credentials.EnvProvider{}, &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database}, &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute}, }) cfg := &aws.Config{ Region: aws.String(req.Region), Credentials: creds, } 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 handleGetMetricStatistics(req *cwRequest, c *middleware.Context) { sess := session.New() creds := credentials.NewChainCredentials( []credentials.Provider{ &credentials.EnvProvider{}, &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database}, &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute}, }) cfg := &aws.Config{ Region: aws.String(req.Region), Credentials: creds, } svc := cloudwatch.New(session.New(cfg), cfg) 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 DeleteDataSource(c *middleware.Context) { id := c.ParamsInt64(":id") if id <= 0 { c.JsonApiErr(400, "Missing valid datasource id", nil) return } cmd := &m.DeleteDataSourceCommand{Id: id, OrgId: c.OrgId} err := bus.Dispatch(cmd) if err != nil { c.JsonApiErr(500, "Failed to delete datasource", err) return } c.JsonOK("Data source deleted") }
func DeleteDashboard(c *middleware.Context) { slug := c.Params(":slug") query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { c.JsonApiErr(404, "Dashboard not found", nil) return } cmd := m.DeleteDashboardCommand{Slug: slug, OrgId: c.OrgId} if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to delete dashboard", err) return } var resp = map[string]interface{}{"title": query.Result.Title} c.JSON(200, resp) }
func GetHomeDashboard(c *middleware.Context) { filePath := path.Join(setting.StaticRootPath, "dashboards/home.json") file, err := os.Open(filePath) if err != nil { c.JsonApiErr(500, "Failed to load home dashboard", err) return } dash := dtos.DashboardFullWithMeta{} dash.Meta.IsHome = true dash.Meta.CanEdit = canEditDashboard(c.OrgRole) jsonParser := json.NewDecoder(file) if err := jsonParser.Decode(&dash.Dashboard); err != nil { c.JsonApiErr(500, "Failed to load home dashboard", err) return } c.JSON(200, &dash) }
func AdminUpdateUserPassword(c *middleware.Context, form dtos.AdminUpdateUserPasswordForm) { userId := c.ParamsInt64(":id") if len(form.Password) < 4 { c.JsonApiErr(400, "New password too short", nil) return } userQuery := m.GetUserByIdQuery{Id: userId} if err := bus.Dispatch(&userQuery); err != nil { c.JsonApiErr(500, "Could not read user from database", err) return } passwordHashed := util.EncodePassword(form.Password, userQuery.Result.Salt) cmd := m.ChangeUserPasswordCommand{ UserId: userId, NewPassword: passwordHashed, } if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "Failed to update user password", err) return } c.JsonOK("User password updated") }
func handleGetDimensions(req *cwRequest, c *middleware.Context) { reqParam := &struct { Parameters struct { Namespace string `json:"namespace"` } `json:"parameters"` }{} json.Unmarshal(req.Body, reqParam) dimensionValues, exists := dimensionsMap[reqParam.Parameters.Namespace] if !exists { c.JsonApiErr(404, "Unable to find dimension "+reqParam.Parameters.Namespace, nil) 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 ProxyDataSourceRequest(c *middleware.Context) { 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.RW(), c.Req.Request) } }
func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) { cmd.OrgId = c.OrgId dash := cmd.GetDashboardModel() if dash.Id == 0 { limitReached, err := middleware.QuotaReached(c, "dashboard") if err != nil { c.JsonApiErr(500, "failed to get quota", err) return } if limitReached { c.JsonApiErr(403, "Quota reached", nil) return } } 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 AdminCreateUser(c *middleware.Context, form dtos.AdminCreateUserForm) { cmd := m.CreateUserCommand{ Login: form.Login, Email: form.Email, Password: form.Password, Name: form.Name, } if len(cmd.Login) == 0 { cmd.Login = cmd.Email if len(cmd.Login) == 0 { c.JsonApiErr(400, "Validation error, need specify either username or email", nil) return } } if len(cmd.Password) < 4 { c.JsonApiErr(400, "Password is missing or too short", nil) return } if err := bus.Dispatch(&cmd); err != nil { c.JsonApiErr(500, "failed to create user", err) return } metrics.M_Api_Admin_User_Create.Inc(1) user := cmd.Result result := m.UserIdDTO{ Message: "User created", Id: user.Id, } c.JSON(200, result) }