Merge branch 'master' into develop

This commit is contained in:
Torkel Ödegaard
2017-11-17 15:49:17 +01:00
177 changed files with 14293 additions and 1263 deletions
+18 -3
View File
@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/util"
)
func GetAnnotations(c *middleware.Context) Response {
@@ -75,9 +76,11 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
return ApiError(500, "Failed to save annotation", err)
}
startID := item.Id
// handle regions
if cmd.IsRegion {
item.RegionId = item.Id
item.RegionId = startID
if item.Data == nil {
item.Data = simplejson.New()
@@ -93,9 +96,18 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
if err := repo.Save(&item); err != nil {
return ApiError(500, "Failed save annotation for region end time", err)
}
return Json(200, util.DynMap{
"message": "Annotation added",
"id": startID,
"endId": item.Id,
})
}
return ApiSuccess("Annotation added")
return Json(200, util.DynMap{
"message": "Annotation added",
"id": startID,
})
}
func formatGraphiteAnnotation(what string, data string) string {
@@ -154,7 +166,10 @@ func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotati
return ApiError(500, "Failed to save Graphite annotation", err)
}
return ApiSuccess("Graphite annotation added")
return Json(200, util.DynMap{
"message": "Graphite annotation added",
"id": item.Id,
})
}
func UpdateAnnotation(c *middleware.Context, cmd dtos.UpdateAnnotationsCmd) Response {
+5 -5
View File
@@ -212,10 +212,10 @@ func (hs *HttpServer) registerRoutes() {
// Data sources
apiRoute.Group("/datasources", func(datasourceRoute RouteRegister) {
datasourceRoute.Get("/", wrap(GetDataSources))
datasourceRoute.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
datasourceRoute.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), wrap(AddDataSource))
datasourceRoute.Put("/:id", bind(m.UpdateDataSourceCommand{}), wrap(UpdateDataSource))
datasourceRoute.Delete("/:id", DeleteDataSourceById)
datasourceRoute.Delete("/name/:name", DeleteDataSourceByName)
datasourceRoute.Delete("/:id", wrap(DeleteDataSourceById))
datasourceRoute.Delete("/name/:name", wrap(DeleteDataSourceByName))
datasourceRoute.Get("/:id", wrap(GetDataSourceById))
datasourceRoute.Get("/name/:name", wrap(GetDataSourceByName))
}, reqOrgAdmin)
@@ -340,8 +340,8 @@ func (hs *HttpServer) registerRoutes() {
r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)
// Gravatar service.
avt := avatar.CacheServer()
r.Get("/avatar/:hash", avt.ServeHTTP)
avatarCacheServer := avatar.NewCacheServer()
r.Get("/avatar/:hash", avatarCacheServer.Handler)
// Websocket
r.Any("/ws", hs.streamManager.Serve)
+16 -11
View File
@@ -24,6 +24,7 @@ import (
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1"
)
var gravatarSource string
@@ -89,12 +90,12 @@ func (this *Avatar) Update() (err error) {
return err
}
type service struct {
type CacheServer struct {
notFound *Avatar
cache map[string]*Avatar
}
func (this *service) mustInt(r *http.Request, defaultValue int, keys ...string) (v int) {
func (this *CacheServer) mustInt(r *http.Request, defaultValue int, keys ...string) (v int) {
for _, k := range keys {
if _, err := fmt.Sscanf(r.FormValue(k), "%d", &v); err == nil {
defaultValue = v
@@ -103,8 +104,8 @@ func (this *service) mustInt(r *http.Request, defaultValue int, keys ...string)
return defaultValue
}
func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
urlPath := r.URL.Path
func (this *CacheServer) Handler(ctx *macaron.Context) {
urlPath := ctx.Req.URL.Path
hash := urlPath[strings.LastIndex(urlPath, "/")+1:]
var avatar *Avatar
@@ -126,20 +127,24 @@ func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
this.cache[hash] = avatar
}
w.Header().Set("Content-Type", "image/jpeg")
w.Header().Set("Content-Length", strconv.Itoa(len(avatar.data.Bytes())))
w.Header().Set("Cache-Control", "private, max-age=3600")
ctx.Resp.Header().Add("Content-Type", "image/jpeg")
if err := avatar.Encode(w); err != nil {
if !setting.EnableGzip {
ctx.Resp.Header().Add("Content-Length", strconv.Itoa(len(avatar.data.Bytes())))
}
ctx.Resp.Header().Add("Cache-Control", "private, max-age=3600")
if err := avatar.Encode(ctx.Resp); err != nil {
log.Warn("avatar encode error: %v", err)
w.WriteHeader(500)
ctx.WriteHeader(500)
}
}
func CacheServer() http.Handler {
func NewCacheServer() *CacheServer {
UpdateGravatarSource()
return &service{
return &CacheServer{
notFound: newNotFound(),
cache: make(map[string]*Avatar),
}
+38 -21
View File
@@ -33,6 +33,7 @@ func GetDataSources(c *middleware.Context) Response {
BasicAuth: ds.BasicAuth,
IsDefault: ds.IsDefault,
JsonData: ds.JsonData,
ReadOnly: ds.ReadOnly,
}
if plugin, exists := plugins.DataSources[ds.Type]; exists {
@@ -68,59 +69,70 @@ func GetDataSourceById(c *middleware.Context) Response {
return Json(200, &dtos)
}
func DeleteDataSourceById(c *middleware.Context) {
func DeleteDataSourceById(c *middleware.Context) Response {
id := c.ParamsInt64(":id")
if id <= 0 {
c.JsonApiErr(400, "Missing valid datasource id", nil)
return
return ApiError(400, "Missing valid datasource id", nil)
}
ds, err := getRawDataSourceById(id, c.OrgId)
if err != nil {
return ApiError(400, "Failed to delete datasource", nil)
}
if ds.ReadOnly {
return ApiError(403, "Cannot delete read-only data source", nil)
}
cmd := &m.DeleteDataSourceByIdCommand{Id: id, OrgId: c.OrgId}
err := bus.Dispatch(cmd)
err = bus.Dispatch(cmd)
if err != nil {
c.JsonApiErr(500, "Failed to delete datasource", err)
return
return ApiError(500, "Failed to delete datasource", err)
}
c.JsonOK("Data source deleted")
return ApiSuccess("Data source deleted")
}
func DeleteDataSourceByName(c *middleware.Context) {
func DeleteDataSourceByName(c *middleware.Context) Response {
name := c.Params(":name")
if name == "" {
c.JsonApiErr(400, "Missing valid datasource name", nil)
return
return ApiError(400, "Missing valid datasource name", nil)
}
getCmd := &m.GetDataSourceByNameQuery{Name: name, OrgId: c.OrgId}
if err := bus.Dispatch(getCmd); err != nil {
return ApiError(500, "Failed to delete datasource", err)
}
if getCmd.Result.ReadOnly {
return ApiError(403, "Cannot delete read-only data source", nil)
}
cmd := &m.DeleteDataSourceByNameCommand{Name: name, OrgId: c.OrgId}
err := bus.Dispatch(cmd)
if err != nil {
c.JsonApiErr(500, "Failed to delete datasource", err)
return
return ApiError(500, "Failed to delete datasource", err)
}
c.JsonOK("Data source deleted")
return ApiSuccess("Data source deleted")
}
func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) {
func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrDataSourceNameExists {
c.JsonApiErr(409, err.Error(), err)
return
return ApiError(409, err.Error(), err)
}
c.JsonApiErr(500, "Failed to add datasource", err)
return
return ApiError(500, "Failed to add datasource", err)
}
ds := convertModelToDtos(cmd.Result)
c.JSON(200, util.DynMap{
return Json(200, util.DynMap{
"message": "Datasource added",
"id": cmd.Result.Id,
"name": cmd.Result.Name,
@@ -160,11 +172,14 @@ func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error {
}
ds, err := getRawDataSourceById(cmd.Id, cmd.OrgId)
if err != nil {
return err
}
if ds.ReadOnly {
return m.ErrDatasourceIsReadOnly
}
secureJsonData := ds.SecureJsonData.Decrypt()
for k, v := range secureJsonData {
@@ -201,6 +216,7 @@ func GetDataSourceByName(c *middleware.Context) Response {
}
dtos := convertModelToDtos(query.Result)
dtos.ReadOnly = true
return Json(200, &dtos)
}
@@ -242,6 +258,7 @@ func convertModelToDtos(ds *m.DataSource) dtos.DataSource {
JsonData: ds.JsonData,
SecureJsonFields: map[string]bool{},
Version: ds.Version,
ReadOnly: ds.ReadOnly,
}
for k, v := range ds.SecureJsonData {
+2
View File
@@ -26,6 +26,7 @@ type DataSource struct {
JsonData *simplejson.Json `json:"jsonData,omitempty"`
SecureJsonFields map[string]bool `json:"secureJsonFields"`
Version int `json:"version"`
ReadOnly bool `json:"readOnly"`
}
type DataSourceListItemDTO struct {
@@ -42,6 +43,7 @@ type DataSourceListItemDTO struct {
BasicAuth bool `json:"basicAuth"`
IsDefault bool `json:"isDefault"`
JsonData *simplejson.Json `json:"jsonData,omitempty"`
ReadOnly bool `json:"readOnly"`
}
type DataSourceList []DataSourceListItemDTO
+2 -1
View File
@@ -146,12 +146,13 @@ func (hs *HttpServer) newMacaron() *macaron.Macaron {
m := macaron.New()
m.Use(middleware.Logger())
m.Use(middleware.Recovery())
if setting.EnableGzip {
m.Use(middleware.Gziper())
}
m.Use(middleware.Recovery())
for _, route := range plugins.StaticRoutes {
pluginRoute := path.Join("/public/plugins/", route.PluginId)
hs.log.Debug("Plugins: Adding route", "route", pluginRoute, "dir", route.Directory)
-2
View File
@@ -81,8 +81,6 @@ func (rr *routeRegister) Register(router Router) *macaron.Router {
}
func (rr *routeRegister) route(pattern, method string, handlers ...macaron.Handler) {
//inject tracing
h := make([]macaron.Handler, 0)
for _, fn := range rr.namedMiddleware {
h = append(h, fn(pattern))