From 3898ea02e60c2811feec65e8ed4c32fea862b632 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 02:22:58 +0100 Subject: [PATCH 01/27] adding created column --- pkg/api/annotations.go | 1 + pkg/services/annotations/annotations.go | 3 +++ pkg/services/sqlstore/annotation.go | 15 ++++++++++++++- .../sqlstore/migrations/annotation_mig.go | 10 ++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index fb75e0bf129..e5a97f340bf 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -24,6 +24,7 @@ func GetAnnotations(c *m.ReqContext) Response { Limit: c.QueryInt64("limit"), Tags: c.QueryStrings("tags"), Type: c.Query("type"), + Sort: c.Query("sort"), } repo := annotations.GetRepository() diff --git a/pkg/services/annotations/annotations.go b/pkg/services/annotations/annotations.go index a6cd7a33318..fd178176ef1 100644 --- a/pkg/services/annotations/annotations.go +++ b/pkg/services/annotations/annotations.go @@ -20,6 +20,7 @@ type ItemQuery struct { RegionId int64 `json:"regionId"` Tags []string `json:"tags"` Type string `json:"type"` + Sort string `json:"sort"` Limit int64 `json:"limit"` } @@ -63,6 +64,7 @@ type Item struct { PrevState string `json:"prevState"` NewState string `json:"newState"` Epoch int64 `json:"epoch"` + Created int64 `json:"created"` Tags []string `json:"tags"` Data *simplejson.Json `json:"data"` @@ -80,6 +82,7 @@ type ItemDTO struct { UserId int64 `json:"userId"` NewState string `json:"newState"` PrevState string `json:"prevState"` + Created int64 `json:"created"` Time int64 `json:"time"` Text string `json:"text"` RegionId int64 `json:"regionId"` diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index 76f1819a18c..65f2abd9a54 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strings" + "time" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/annotations" @@ -17,6 +18,7 @@ func (r *SqlAnnotationRepo) Save(item *annotations.Item) error { return inTransaction(func(sess *DBSession) error { tags := models.ParseTagPairs(item.Tags) item.Tags = models.JoinTagPairs(tags) + item.Created = time.Now().UnixNano() / int64(time.Millisecond) if _, err := sess.Table("annotation").Insert(item); err != nil { return err } @@ -127,6 +129,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I annotation.text, annotation.tags, annotation.data, + annotation.created, usr.email, usr.login, alert.name as alert_name @@ -205,7 +208,17 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I query.Limit = 10 } - sql.WriteString(fmt.Sprintf(" ORDER BY epoch DESC LIMIT %v", query.Limit)) + var sort string = "epoch DESC" + switch query.Sort { + case "time.asc": + sort = "epoch ASC" + case "created": + sort = "annotation.created DESC" + case "created.asc": + sort = "annotation.created ASC" + } + + sql.WriteString(fmt.Sprintf(" ORDER BY %s LIMIT %v", sort, query.Limit)) items := make([]*annotations.ItemDTO, 0) diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index 8d2bf94bc42..24e2beb2eda 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -90,4 +90,14 @@ func addAnnotationMig(mg *Migrator) { Sqlite(updateTextFieldSql). Postgres(updateTextFieldSql). Mysql(updateTextFieldSql)) + + // + // Add a 'created' column + // + mg.AddMigration("Add created time to annotation table", NewAddColumnMigration(table, &Column{ + Name: "created", Type: DB_BigInt, Nullable: true, Default: "0", + })) + mg.AddMigration("Add index for created in annotation table", NewAddIndexMigration(table, &Index{ + Cols: []string{"org_id", "created"}, Type: IndexType, + })) } From a2bbd89a9ebb73cd445bc920b0dbda02aa2cb31d Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 15:52:09 +0100 Subject: [PATCH 02/27] adding updated column --- CHANGELOG.md | 1 + docs/sources/http_api/annotations.md | 2 ++ pkg/api/annotations.go | 2 +- pkg/services/annotations/annotations.go | 4 ++- pkg/services/sqlstore/annotation.go | 26 +++++++++++-------- .../sqlstore/migrations/annotation_mig.go | 8 +++++- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 304b1ba6d0b..001433fa652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * **Alerting**: Support Pagerduty notification channel using Pagerduty V2 API [#10531](https://github.com/grafana/grafana/issues/10531), thx [@jbaublitz](https://github.com/jbaublitz) * **Templating**: Add comma templating format [#10632](https://github.com/grafana/grafana/issues/10632), thx [@mtanda](https://github.com/mtanda) * **Prometheus**: Support POST for query and query_range [#9859](https://github.com/grafana/grafana/pull/9859), thx [@mtanda](https://github.com/mtanda) +* **Annotations API**: Record creation/update times and add more query options [#11333](https://github.com/grafana/grafana/pull/11333), thx [@mtanda](https://github.com/ryantxu) ### Minor * **OpsGenie**: Add triggered alerts as description [#11046](https://github.com/grafana/grafana/pull/11046), thx [@llamashoes](https://github.com/llamashoes) diff --git a/docs/sources/http_api/annotations.md b/docs/sources/http_api/annotations.md index 19c2a5c386c..c26b7d72a4b 100644 --- a/docs/sources/http_api/annotations.md +++ b/docs/sources/http_api/annotations.md @@ -36,6 +36,8 @@ Query Parameters: - `alertId`: number. Optional. Find annotations for a specified alert. - `dashboardId`: number. Optional. Find annotations that are scoped to a specific dashboard - `panelId`: number. Optional. Find annotations that are scoped to a specific panel +- `userId`: number. Optional. Find annotations created by a specific user +- `type`: string. Optional. `alert`|`annotation` Return alerts or user created annotations - `tags`: string. Optional. Use this to filter global annotations. Global annotations are annotations from an annotation data source that are not connected specifically to a dashboard or panel. To do an "AND" filtering with multiple tags, specify the tags parameter multiple times e.g. `tags=tag1&tags=tag2`. **Example Response**: diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 123a8432f13..5762d56548a 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -18,13 +18,13 @@ func GetAnnotations(c *m.ReqContext) Response { From: c.QueryInt64("from") / 1000, To: c.QueryInt64("to") / 1000, OrgId: c.OrgId, + UserId: c.QueryInt64("userId"), AlertId: c.QueryInt64("alertId"), DashboardId: c.QueryInt64("dashboardId"), PanelId: c.QueryInt64("panelId"), Limit: c.QueryInt64("limit"), Tags: c.QueryStrings("tags"), Type: c.Query("type"), - Sort: c.Query("sort"), } repo := annotations.GetRepository() diff --git a/pkg/services/annotations/annotations.go b/pkg/services/annotations/annotations.go index fd178176ef1..5cebb3d2df9 100644 --- a/pkg/services/annotations/annotations.go +++ b/pkg/services/annotations/annotations.go @@ -13,6 +13,7 @@ type ItemQuery struct { OrgId int64 `json:"orgId"` From int64 `json:"from"` To int64 `json:"to"` + UserId int64 `json:"userId"` AlertId int64 `json:"alertId"` DashboardId int64 `json:"dashboardId"` PanelId int64 `json:"panelId"` @@ -20,7 +21,6 @@ type ItemQuery struct { RegionId int64 `json:"regionId"` Tags []string `json:"tags"` Type string `json:"type"` - Sort string `json:"sort"` Limit int64 `json:"limit"` } @@ -65,6 +65,7 @@ type Item struct { NewState string `json:"newState"` Epoch int64 `json:"epoch"` Created int64 `json:"created"` + Updated int64 `json:"updated"` Tags []string `json:"tags"` Data *simplejson.Json `json:"data"` @@ -83,6 +84,7 @@ type ItemDTO struct { NewState string `json:"newState"` PrevState string `json:"prevState"` Created int64 `json:"created"` + Updated int64 `json:"updated"` Time int64 `json:"time"` Text string `json:"text"` RegionId int64 `json:"regionId"` diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index 65f2abd9a54..ebba2083576 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -15,10 +15,14 @@ type SqlAnnotationRepo struct { } func (r *SqlAnnotationRepo) Save(item *annotations.Item) error { + if item.DashboardId == 0 { + return errors.New("Annotation is missing dashboard_id") + } return inTransaction(func(sess *DBSession) error { tags := models.ParseTagPairs(item.Tags) item.Tags = models.JoinTagPairs(tags) item.Created = time.Now().UnixNano() / int64(time.Millisecond) + item.Updated = item.Created if _, err := sess.Table("annotation").Insert(item); err != nil { return err } @@ -66,6 +70,7 @@ func (r *SqlAnnotationRepo) Update(item *annotations.Item) error { err error ) existing := new(annotations.Item) + item.Updated = time.Now().UnixNano() / int64(time.Millisecond) if item.Id == 0 && item.RegionId != 0 { // Update region end time @@ -130,6 +135,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I annotation.tags, annotation.data, annotation.created, + annotation.updated, usr.email, usr.login, alert.name as alert_name @@ -167,6 +173,11 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I params = append(params, query.PanelId) } + if query.UserId != 0 { + sql.WriteString(` AND annotation.user_id = ?`) + params = append(params, query.UserId) + } + if query.From > 0 && query.To > 0 { sql.WriteString(` AND annotation.epoch BETWEEN ? AND ?`) params = append(params, query.From, query.To) @@ -175,6 +186,9 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I if query.Type == "alert" { sql.WriteString(` AND annotation.alert_id > 0`) } + if query.Type == "annotation" { + sql.WriteString(` AND annotation.alert_id = 0`) + } if len(query.Tags) > 0 { keyValueFilters := []string{} @@ -208,17 +222,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I query.Limit = 10 } - var sort string = "epoch DESC" - switch query.Sort { - case "time.asc": - sort = "epoch ASC" - case "created": - sort = "annotation.created DESC" - case "created.asc": - sort = "annotation.created ASC" - } - - sql.WriteString(fmt.Sprintf(" ORDER BY %s LIMIT %v", sort, query.Limit)) + sql.WriteString(fmt.Sprintf(" ORDER BY epoch DESC LIMIT %v", query.Limit)) items := make([]*annotations.ItemDTO, 0) diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index 24e2beb2eda..11cc986d669 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -92,12 +92,18 @@ func addAnnotationMig(mg *Migrator) { Mysql(updateTextFieldSql)) // - // Add a 'created' column + // Add a 'created' & 'updated' column // mg.AddMigration("Add created time to annotation table", NewAddColumnMigration(table, &Column{ Name: "created", Type: DB_BigInt, Nullable: true, Default: "0", })) + mg.AddMigration("Add updated time to annotation table", NewAddColumnMigration(table, &Column{ + Name: "updated", Type: DB_BigInt, Nullable: true, Default: "0", + })) mg.AddMigration("Add index for created in annotation table", NewAddIndexMigration(table, &Index{ Cols: []string{"org_id", "created"}, Type: IndexType, })) + mg.AddMigration("Add index for updated in annotation table", NewAddIndexMigration(table, &Index{ + Cols: []string{"org_id", "updated"}, Type: IndexType, + })) } From 20353db9660fdc3df31bd85041f87f2c954dd8dd Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 16:21:47 +0100 Subject: [PATCH 03/27] convert epoch to milliseconds --- pkg/api/annotations.go | 22 ++++++------------- pkg/services/sqlstore/annotation.go | 9 +++++--- .../sqlstore/migrations/annotation_mig.go | 9 ++++++++ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 5762d56548a..e17cabb01a1 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -2,7 +2,6 @@ package api import ( "strings" - "time" "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/components/simplejson" @@ -15,8 +14,8 @@ import ( func GetAnnotations(c *m.ReqContext) Response { query := &annotations.ItemQuery{ - From: c.QueryInt64("from") / 1000, - To: c.QueryInt64("to") / 1000, + From: c.QueryInt64("from"), + To: c.QueryInt64("to"), OrgId: c.OrgId, UserId: c.QueryInt64("userId"), AlertId: c.QueryInt64("alertId"), @@ -38,7 +37,7 @@ func GetAnnotations(c *m.ReqContext) Response { if item.Email != "" { item.AvatarUrl = dtos.GetGravatarUrl(item.Email) } - item.Time = item.Time * 1000 + item.Time = item.Time } return Json(200, items) @@ -69,16 +68,12 @@ func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response { UserId: c.UserId, DashboardId: cmd.DashboardId, PanelId: cmd.PanelId, - Epoch: cmd.Time / 1000, + Epoch: cmd.Time, Text: cmd.Text, Data: cmd.Data, Tags: cmd.Tags, } - if item.Epoch == 0 { - item.Epoch = time.Now().Unix() - } - if err := repo.Save(&item); err != nil { return ApiError(500, "Failed to save annotation", err) } @@ -98,7 +93,7 @@ func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response { } item.Id = 0 - item.Epoch = cmd.TimeEnd / 1000 + item.Epoch = cmd.TimeEnd if err := repo.Save(&item); err != nil { return ApiError(500, "Failed save annotation for region end time", err) @@ -133,9 +128,6 @@ func PostGraphiteAnnotation(c *m.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd return ApiError(500, "Failed to save Graphite annotation", err) } - if cmd.When == 0 { - cmd.When = time.Now().Unix() - } text := formatGraphiteAnnotation(cmd.What, cmd.Data) // Support tags in prior to Graphite 0.10.0 format (string of tags separated by space) @@ -192,7 +184,7 @@ func UpdateAnnotation(c *m.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response { OrgId: c.OrgId, UserId: c.UserId, Id: annotationID, - Epoch: cmd.Time / 1000, + Epoch: cmd.Time, Text: cmd.Text, Tags: cmd.Tags, } @@ -204,7 +196,7 @@ func UpdateAnnotation(c *m.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response { if cmd.IsRegion { itemRight := item itemRight.RegionId = item.Id - itemRight.Epoch = cmd.TimeEnd / 1000 + itemRight.Epoch = cmd.TimeEnd // We don't know id of region right event, so set it to 0 and find then using query like // ... WHERE region_id = AND id != ... diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index ebba2083576..5906be3736b 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -23,6 +23,10 @@ func (r *SqlAnnotationRepo) Save(item *annotations.Item) error { item.Tags = models.JoinTagPairs(tags) item.Created = time.Now().UnixNano() / int64(time.Millisecond) item.Updated = item.Created + if item.Epoch == 0 { + item.Epoch = item.Created + } + if _, err := sess.Table("annotation").Insert(item); err != nil { return err } @@ -70,7 +74,6 @@ func (r *SqlAnnotationRepo) Update(item *annotations.Item) error { err error ) existing := new(annotations.Item) - item.Updated = time.Now().UnixNano() / int64(time.Millisecond) if item.Id == 0 && item.RegionId != 0 { // Update region end time @@ -86,6 +89,7 @@ func (r *SqlAnnotationRepo) Update(item *annotations.Item) error { return errors.New("Annotation not found") } + existing.Updated = time.Now().UnixNano() / int64(time.Millisecond) existing.Epoch = item.Epoch existing.Text = item.Text if item.RegionId != 0 { @@ -185,8 +189,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I if query.Type == "alert" { sql.WriteString(` AND annotation.alert_id > 0`) - } - if query.Type == "annotation" { + } else if query.Type == "annotation" { sql.WriteString(` AND annotation.alert_id = 0`) } diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index 11cc986d669..89fccad0d09 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -106,4 +106,13 @@ func addAnnotationMig(mg *Migrator) { mg.AddMigration("Add index for updated in annotation table", NewAddIndexMigration(table, &Index{ Cols: []string{"org_id", "updated"}, Type: IndexType, })) + + // + // Convert epoch saved as seconds to miliseconds + // + updateEpochSql := "UPDATE annotation SET epoch = (epoch*1000)" + mg.AddMigration("Convert existing annotations from seconds to miliseconds", new(RawSqlMigration). + Sqlite(updateEpochSql). + Postgres(updateEpochSql). + Mysql(updateEpochSql)) } From db91033b6e2fa09269f6a9ce4983957c46290914 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 19:33:33 +0100 Subject: [PATCH 04/27] adding tests, but they arent running locally --- pkg/services/sqlstore/annotation_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/services/sqlstore/annotation_test.go b/pkg/services/sqlstore/annotation_test.go index d5cee110b9a..e76e1802b75 100644 --- a/pkg/services/sqlstore/annotation_test.go +++ b/pkg/services/sqlstore/annotation_test.go @@ -79,6 +79,12 @@ func TestAnnotations(t *testing.T) { Convey("Can read tags", func() { So(items[0].Tags, ShouldResemble, []string{"outage", "error", "type:outage", "server:server-1"}) }) + + Convey("Has created and updated values", func() { + So(items[0].created, ShouldBeGreaterThan, 0) + So(items[0].updated, ShouldBeGreaterThan, 0) + So(items[0].created, ShouldBeEqual, items[1].created) + }) }) Convey("Can query for annotation by id", func() { @@ -231,6 +237,10 @@ func TestAnnotations(t *testing.T) { So(items[0].Tags, ShouldResemble, []string{"newtag1", "newtag2"}) So(items[0].Text, ShouldEqual, "something new") }) + + Convey("Updated time has increased", func() { + So(items[0].updated, ShouldBeGreaterThan, items[0].created) + }) }) Convey("Can delete annotation", func() { From fa021b547a4a455e54d979096d23d91e2d7d3835 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 19:39:30 +0100 Subject: [PATCH 05/27] using circle as my tester --- pkg/services/sqlstore/annotation_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/services/sqlstore/annotation_test.go b/pkg/services/sqlstore/annotation_test.go index e76e1802b75..8a12c092cbe 100644 --- a/pkg/services/sqlstore/annotation_test.go +++ b/pkg/services/sqlstore/annotation_test.go @@ -81,9 +81,9 @@ func TestAnnotations(t *testing.T) { }) Convey("Has created and updated values", func() { - So(items[0].created, ShouldBeGreaterThan, 0) - So(items[0].updated, ShouldBeGreaterThan, 0) - So(items[0].created, ShouldBeEqual, items[1].created) + So(items[0].Created, ShouldBeGreaterThan, 0) + So(items[0].Updated, ShouldBeGreaterThan, 0) + So(items[0].Updated, ShouldBeEqual, items[1].Created) }) }) @@ -239,7 +239,7 @@ func TestAnnotations(t *testing.T) { }) Convey("Updated time has increased", func() { - So(items[0].updated, ShouldBeGreaterThan, items[0].created) + So(items[0].Updated, ShouldBeGreaterThan, items[0].Created) }) }) From d554c6f9be97818b5df17ed19a23ec5cde9f611a Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 19:44:47 +0100 Subject: [PATCH 06/27] using circle as my tester --- pkg/services/sqlstore/annotation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/annotation_test.go b/pkg/services/sqlstore/annotation_test.go index 8a12c092cbe..c8d733b5ae9 100644 --- a/pkg/services/sqlstore/annotation_test.go +++ b/pkg/services/sqlstore/annotation_test.go @@ -83,7 +83,7 @@ func TestAnnotations(t *testing.T) { Convey("Has created and updated values", func() { So(items[0].Created, ShouldBeGreaterThan, 0) So(items[0].Updated, ShouldBeGreaterThan, 0) - So(items[0].Updated, ShouldBeEqual, items[1].Created) + So(items[0].Updated, ShouldEqual, items[1].Created) }) }) From 0c7294593cf58c7b249ce6429ae47d4e2cebfc9a Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 20:05:04 +0100 Subject: [PATCH 07/27] update the updated column! --- pkg/services/sqlstore/annotation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index 5906be3736b..0ad531a1dd6 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -113,7 +113,7 @@ func (r *SqlAnnotationRepo) Update(item *annotations.Item) error { existing.Tags = item.Tags - if _, err := sess.Table("annotation").Id(existing.Id).Cols("epoch", "text", "region_id", "tags").Update(existing); err != nil { + if _, err := sess.Table("annotation").Id(existing.Id).Cols("epoch", "text", "region_id", "updated", "tags").Update(existing); err != nil { return err } From 164ddb16c930bd3edfebdd9021ec7e8e3f393154 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 22 Mar 2018 20:48:40 +0100 Subject: [PATCH 08/27] dooh --- pkg/services/sqlstore/annotation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/annotation_test.go b/pkg/services/sqlstore/annotation_test.go index c8d733b5ae9..5af5f271993 100644 --- a/pkg/services/sqlstore/annotation_test.go +++ b/pkg/services/sqlstore/annotation_test.go @@ -83,7 +83,7 @@ func TestAnnotations(t *testing.T) { Convey("Has created and updated values", func() { So(items[0].Created, ShouldBeGreaterThan, 0) So(items[0].Updated, ShouldBeGreaterThan, 0) - So(items[0].Updated, ShouldEqual, items[1].Created) + So(items[0].Updated, ShouldEqual, items[0].Created) }) }) From db92a96067463258516b171e0b8946fb39dcf4ff Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 11:36:44 +0100 Subject: [PATCH 09/27] move dashboard error to API (not sql) --- pkg/api/annotations.go | 5 +++++ pkg/api/annotations_test.go | 29 +++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index e17cabb01a1..2c303f22b2b 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -63,6 +63,11 @@ func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response { return ApiError(500, "Failed to save annotation", err) } + if cmd.DashboardId == 0 { + err := &CreateAnnotationError{"Missing DashboardID"} + return ApiError(500, "Failed to save annotation", err) + } + item := annotations.Item{ OrgId: c.OrgId, UserId: c.UserId, diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 7c298550673..bb891e012d2 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -14,10 +14,11 @@ import ( func TestAnnotationsApiEndpoint(t *testing.T) { Convey("Given an annotation without a dashboard id", t, func() { cmd := dtos.PostAnnotationsCmd{ - Time: 1000, - Text: "annotation text", - Tags: []string{"tag1", "tag2"}, - IsRegion: false, + DashboardId: 1, + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, } updateCmd := dtos.UpdateAnnotationsCmd{ @@ -79,6 +80,26 @@ func TestAnnotationsApiEndpoint(t *testing.T) { So(sc.resp.Code, ShouldEqual, 200) }) }) + + Convey("Should note be able to save an annotation", func() { + cmd := dtos.PostAnnotationsCmd{ + Time: 1000, + Text: "annotation text", + } + postAnnotationScenario("When calling POST without dashboardId", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 500) + }) + + cmd := dtos.PostAnnotationsCmd{ + Time: 1000, + DashboardId: 3, + } + postAnnotationScenario("When calling POST without text", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 500) + }) + }) }) }) From a0a6fa6fa54932b05bd5653504ef725661e23387 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 11:47:07 +0100 Subject: [PATCH 10/27] remove constraint from sqlstore --- pkg/services/sqlstore/annotation.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index 0ad531a1dd6..502ebbd3d02 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -15,9 +15,6 @@ type SqlAnnotationRepo struct { } func (r *SqlAnnotationRepo) Save(item *annotations.Item) error { - if item.DashboardId == 0 { - return errors.New("Annotation is missing dashboard_id") - } return inTransaction(func(sess *DBSession) error { tags := models.ParseTagPairs(item.Tags) item.Tags = models.JoinTagPairs(tags) From b39fb7fdd55a3389807c0db10cf2d14389adb0fb Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 12:01:21 +0100 Subject: [PATCH 11/27] fix operator --- pkg/api/annotations_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index bb891e012d2..8e09b4a41a6 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -82,7 +82,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) { }) Convey("Should note be able to save an annotation", func() { - cmd := dtos.PostAnnotationsCmd{ + cmd = dtos.PostAnnotationsCmd{ Time: 1000, Text: "annotation text", } @@ -91,7 +91,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) { So(sc.resp.Code, ShouldEqual, 500) }) - cmd := dtos.PostAnnotationsCmd{ + cmd = dtos.PostAnnotationsCmd{ Time: 1000, DashboardId: 3, } From 14b737e662a004a26f9d5a949b3d3dd770d4bc0e Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 12:08:32 +0100 Subject: [PATCH 12/27] update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d601469be0a..afcd16c9ef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ * **Alerting**: Support Pagerduty notification channel using Pagerduty V2 API [#10531](https://github.com/grafana/grafana/issues/10531), thx [@jbaublitz](https://github.com/jbaublitz) * **Templating**: Add comma templating format [#10632](https://github.com/grafana/grafana/issues/10632), thx [@mtanda](https://github.com/mtanda) * **Prometheus**: Support POST for query and query_range [#9859](https://github.com/grafana/grafana/pull/9859), thx [@mtanda](https://github.com/mtanda) -* **Annotations API**: Record creation/update times and add more query options [#11333](https://github.com/grafana/grafana/pull/11333), thx [@mtanda](https://github.com/ryantxu) +* **Annotations API**: Save creation/update times and add more query options [#11333](https://github.com/grafana/grafana/pull/11333), thx [@ryantxu](https://github.com/ryantxu) ### Minor * **OpsGenie**: Add triggered alerts as description [#11046](https://github.com/grafana/grafana/pull/11046), thx [@llamashoes](https://github.com/llamashoes) From a58b4ff2d636daa6f096caa269510db997465085 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 12:13:38 +0100 Subject: [PATCH 13/27] remove api tests --- pkg/api/annotations_test.go | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 8e09b4a41a6..7c298550673 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -14,11 +14,10 @@ import ( func TestAnnotationsApiEndpoint(t *testing.T) { Convey("Given an annotation without a dashboard id", t, func() { cmd := dtos.PostAnnotationsCmd{ - DashboardId: 1, - Time: 1000, - Text: "annotation text", - Tags: []string{"tag1", "tag2"}, - IsRegion: false, + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, } updateCmd := dtos.UpdateAnnotationsCmd{ @@ -80,26 +79,6 @@ func TestAnnotationsApiEndpoint(t *testing.T) { So(sc.resp.Code, ShouldEqual, 200) }) }) - - Convey("Should note be able to save an annotation", func() { - cmd = dtos.PostAnnotationsCmd{ - Time: 1000, - Text: "annotation text", - } - postAnnotationScenario("When calling POST without dashboardId", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { - sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() - So(sc.resp.Code, ShouldEqual, 500) - }) - - cmd = dtos.PostAnnotationsCmd{ - Time: 1000, - DashboardId: 3, - } - postAnnotationScenario("When calling POST without text", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { - sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() - So(sc.resp.Code, ShouldEqual, 500) - }) - }) }) }) From 2116152295332b6d29f1145e530c4419e9094729 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 12:35:39 +0100 Subject: [PATCH 14/27] add dashboardId to test --- pkg/api/annotations_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 7c298550673..02878750b28 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -14,10 +14,11 @@ import ( func TestAnnotationsApiEndpoint(t *testing.T) { Convey("Given an annotation without a dashboard id", t, func() { cmd := dtos.PostAnnotationsCmd{ - Time: 1000, - Text: "annotation text", - Tags: []string{"tag1", "tag2"}, - IsRegion: false, + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, + DashboardId: 1, } updateCmd := dtos.UpdateAnnotationsCmd{ From e92ea79524f6fa5aac85c4bac9ecc9792d1c2bc2 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 12:48:03 +0100 Subject: [PATCH 15/27] get circle to run tests again --- pkg/api/annotations_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 02878750b28..94dfec10ddb 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -18,7 +18,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) { Text: "annotation text", Tags: []string{"tag1", "tag2"}, IsRegion: false, - DashboardId: 1, + DashboardId: 5, } updateCmd := dtos.UpdateAnnotationsCmd{ From 7defb1adf583de6d086fde2c16475523c4c13dc0 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 23 Mar 2018 12:54:53 +0100 Subject: [PATCH 16/27] remove dashboardId check... i can't figure out how the tests work --- pkg/api/annotations.go | 5 ----- pkg/api/annotations_test.go | 9 ++++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 2c303f22b2b..e17cabb01a1 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -63,11 +63,6 @@ func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response { return ApiError(500, "Failed to save annotation", err) } - if cmd.DashboardId == 0 { - err := &CreateAnnotationError{"Missing DashboardID"} - return ApiError(500, "Failed to save annotation", err) - } - item := annotations.Item{ OrgId: c.OrgId, UserId: c.UserId, diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 94dfec10ddb..7c298550673 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -14,11 +14,10 @@ import ( func TestAnnotationsApiEndpoint(t *testing.T) { Convey("Given an annotation without a dashboard id", t, func() { cmd := dtos.PostAnnotationsCmd{ - Time: 1000, - Text: "annotation text", - Tags: []string{"tag1", "tag2"}, - IsRegion: false, - DashboardId: 5, + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, } updateCmd := dtos.UpdateAnnotationsCmd{ From eabcbcda88f7118a4fd381fceee547ddd3f008f2 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 24 Mar 2018 11:39:20 +0100 Subject: [PATCH 17/27] remove README changes --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afcd16c9ef3..1df6266c763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ * **Alerting**: Support Pagerduty notification channel using Pagerduty V2 API [#10531](https://github.com/grafana/grafana/issues/10531), thx [@jbaublitz](https://github.com/jbaublitz) * **Templating**: Add comma templating format [#10632](https://github.com/grafana/grafana/issues/10632), thx [@mtanda](https://github.com/mtanda) * **Prometheus**: Support POST for query and query_range [#9859](https://github.com/grafana/grafana/pull/9859), thx [@mtanda](https://github.com/mtanda) -* **Annotations API**: Save creation/update times and add more query options [#11333](https://github.com/grafana/grafana/pull/11333), thx [@ryantxu](https://github.com/ryantxu) +* **Alerting**: Add support for retries on alert queries [#5855](https://github.com/grafana/grafana/issues/5855), thx [@Thib17](https://github.com/Thib17) ### Minor * **OpsGenie**: Add triggered alerts as description [#11046](https://github.com/grafana/grafana/pull/11046), thx [@llamashoes](https://github.com/llamashoes) From 66d020eb7eb07d9b37819f3c16265c8c3675d5d8 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 5 Apr 2018 09:51:08 +0200 Subject: [PATCH 18/27] skip migration if it is a big number --- pkg/services/sqlstore/migrations/annotation_mig.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index 89fccad0d09..7fac0001e5b 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -110,8 +110,8 @@ func addAnnotationMig(mg *Migrator) { // // Convert epoch saved as seconds to miliseconds // - updateEpochSql := "UPDATE annotation SET epoch = (epoch*1000)" - mg.AddMigration("Convert existing annotations from seconds to miliseconds", new(RawSqlMigration). + updateEpochSql := "UPDATE annotation SET epoch = (epoch*1000) where epoch < 9999999999" + mg.AddMigration("Convert existing annotations from seconds to milliseconds", new(RawSqlMigration). Sqlite(updateEpochSql). Postgres(updateEpochSql). Mysql(updateEpochSql)) From 60816f5fc2e1fe6a0856a1d4e1bf13441878498d Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 9 Apr 2018 12:48:01 +0200 Subject: [PATCH 19/27] using millis for annotations too --- pkg/services/alerting/result_handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 8f9deb758a6..4b337c858bb 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -77,7 +77,7 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error { Text: "", NewState: string(evalContext.Rule.State), PrevState: string(evalContext.PrevAlertState), - Epoch: time.Now().Unix(), + Epoch: time.Now().UnixNano() / int64(time.Millisecond), Data: annotationData, } From 5ca972542bd71353233bcd910e405655e2af14e1 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 9 Apr 2018 13:58:09 +0200 Subject: [PATCH 20/27] convert graphite epoch to ms --- pkg/api/annotations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index bc982fa84ea..fdf577a6a6f 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -156,7 +156,7 @@ func PostGraphiteAnnotation(c *m.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd item := annotations.Item{ OrgId: c.OrgId, UserId: c.UserId, - Epoch: cmd.When, + Epoch: cmd.When * 1000, Text: text, Tags: tagsArray, } From e794951087043783655d8e4ab811a0edf89f559e Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 18 Apr 2018 10:21:48 +0200 Subject: [PATCH 21/27] removed padding and moved carrot --- public/sass/components/_gf-form.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/sass/components/_gf-form.scss b/public/sass/components/_gf-form.scss index 6603cfa072b..7a3046444fe 100644 --- a/public/sass/components/_gf-form.scss +++ b/public/sass/components/_gf-form.scss @@ -341,19 +341,19 @@ $input-border: 1px solid $input-border-color; margin-right: $gf-form-margin; position: relative; background-color: $input-bg; - padding-right: $input-padding-x; border: $input-border; border-radius: $input-border-radius; &::after { position: absolute; top: 35%; - right: $input-padding-x/2; + right: $input-padding-x; background-color: transparent; color: $input-color; font: normal normal normal $font-size-sm/1 FontAwesome; content: '\f0d7'; pointer-events: none; + font-size: 11px; } .gf-form-input { From 03a9650c575cb641f4923007f0348aa6a0142d0f Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 20 Apr 2018 09:52:25 +0200 Subject: [PATCH 22/27] cli: adds os and arch headers this makes it possible for the plugin repo to provide the correct package if arch and os matters --- pkg/cmd/grafana-cli/services/services.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/cmd/grafana-cli/services/services.go b/pkg/cmd/grafana-cli/services/services.go index 3745dbff90e..e743d42022c 100644 --- a/pkg/cmd/grafana-cli/services/services.go +++ b/pkg/cmd/grafana-cli/services/services.go @@ -10,6 +10,7 @@ import ( "net/http" "net/url" "path" + "runtime" "time" "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" @@ -155,6 +156,8 @@ func sendRequest(repoUrl string, subPaths ...string) ([]byte, error) { req, err := http.NewRequest(http.MethodGet, u.String(), nil) req.Header.Set("grafana-version", grafanaVersion) + req.Header.Set("grafana-os", runtime.GOOS) + req.Header.Set("grafana-arch", runtime.GOARCH) req.Header.Set("User-Agent", "grafana "+grafanaVersion) if err != nil { From 98bbb0189892980e8d05b81e50a7ab73132cd790 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 20 Apr 2018 10:35:15 +0200 Subject: [PATCH 23/27] build: removes gometalinter for some reason the linter lints files in /vendor which it should not. So we have to remove it until it works as expected ref #10381 --- .circleci/config.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 603c5fe0720..e7f40419402 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -139,10 +139,6 @@ workflows: filters: tags: only: /.*/ - - gometalinter: - filters: - tags: - only: /.*/ - build: filters: tags: From cdbd4e0fc0539293e3949e0a34f3ddafa413cda7 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 18 Apr 2018 15:54:42 +0200 Subject: [PATCH 24/27] graphite: convert ds test to jest --- ...datasource_specs.ts => datasource.jest.ts} | 156 ++++++++---------- 1 file changed, 68 insertions(+), 88 deletions(-) rename public/app/plugins/datasource/graphite/specs/{datasource_specs.ts => datasource.jest.ts} (57%) diff --git a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts b/public/app/plugins/datasource/graphite/specs/datasource.jest.ts similarity index 57% rename from public/app/plugins/datasource/graphite/specs/datasource_specs.ts rename to public/app/plugins/datasource/graphite/specs/datasource.jest.ts index 0fb68d06498..dac6c2252d8 100644 --- a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/graphite/specs/datasource.jest.ts @@ -1,30 +1,19 @@ -import { describe, beforeEach, it, expect, angularMocks } from 'test/lib/common'; -import helpers from 'test/specs/helpers'; import { GraphiteDatasource } from '../datasource'; import moment from 'moment'; import _ from 'lodash'; +import $q from 'q'; +import { TemplateSrvStub } from 'test/specs/helpers'; -describe('graphiteDatasource', function() { - let ctx = new helpers.ServiceTestContext(); - let instanceSettings: any = { url: [''], name: 'graphiteProd', jsonData: {} }; - - beforeEach(angularMocks.module('grafana.core')); - beforeEach(angularMocks.module('grafana.services')); - beforeEach(ctx.providePhase(['backendSrv', 'templateSrv'])); - beforeEach( - angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { - ctx.$q = $q; - ctx.$httpBackend = $httpBackend; - ctx.$rootScope = $rootScope; - ctx.$injector = $injector; - $httpBackend.when('GET', /\.html$/).respond(''); - }) - ); +describe('graphiteDatasource', () => { + let ctx: any = { + backendSrv: {}, + $q: $q, + templateSrv: new TemplateSrvStub(), + }; beforeEach(function() { - ctx.ds = ctx.$injector.instantiate(GraphiteDatasource, { - instanceSettings: instanceSettings, - }); + ctx.instanceSettings = { url: [''], name: 'graphiteProd', jsonData: {} }; + ctx.ds = new GraphiteDatasource(ctx.instanceSettings, ctx.$q, ctx.backendSrv, ctx.templateSrv); }); describe('When querying graphite with one target using query editor target spec', function() { @@ -38,7 +27,7 @@ describe('graphiteDatasource', function() { let results; let requestOptions; - beforeEach(function() { + beforeEach(async () => { ctx.backendSrv.datasourceRequest = function(options) { requestOptions = options; return ctx.$q.when({ @@ -46,40 +35,39 @@ describe('graphiteDatasource', function() { }); }; - ctx.ds.query(query).then(function(data) { + await ctx.ds.query(query).then(function(data) { results = data; }); - ctx.$rootScope.$apply(); }); it('should generate the correct query', function() { - expect(requestOptions.url).to.be('/render'); + expect(requestOptions.url).toBe('/render'); }); it('should set unique requestId', function() { - expect(requestOptions.requestId).to.be('graphiteProd.panelId.3'); + expect(requestOptions.requestId).toBe('graphiteProd.panelId.3'); }); it('should query correctly', function() { let params = requestOptions.data.split('&'); - expect(params).to.contain('target=prod1.count'); - expect(params).to.contain('target=prod2.count'); - expect(params).to.contain('from=-1h'); - expect(params).to.contain('until=now'); + expect(params).toContain('target=prod1.count'); + expect(params).toContain('target=prod2.count'); + expect(params).toContain('from=-1h'); + expect(params).toContain('until=now'); }); it('should exclude undefined params', function() { let params = requestOptions.data.split('&'); - expect(params).to.not.contain('cacheTimeout=undefined'); + expect(params).not.toContain('cacheTimeout=undefined'); }); it('should return series list', function() { - expect(results.data.length).to.be(1); - expect(results.data[0].target).to.be('prod1.count'); + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('prod1.count'); }); it('should convert to millisecond resolution', function() { - expect(results.data[0].datapoints[0][0]).to.be(10); + expect(results.data[0].datapoints[0][0]).toBe(10); }); }); @@ -110,22 +98,21 @@ describe('graphiteDatasource', function() { ], }; - beforeEach(() => { + beforeEach(async () => { ctx.backendSrv.datasourceRequest = function(options) { return ctx.$q.when(response); }; - ctx.ds.annotationQuery(options).then(function(data) { + await ctx.ds.annotationQuery(options).then(function(data) { results = data; }); - ctx.$rootScope.$apply(); }); it('should parse the tags string into an array', () => { - expect(_.isArray(results[0].tags)).to.eql(true); - expect(results[0].tags.length).to.eql(2); - expect(results[0].tags[0]).to.eql('tag1'); - expect(results[0].tags[1]).to.eql('tag2'); + expect(_.isArray(results[0].tags)).toEqual(true); + expect(results[0].tags.length).toEqual(2); + expect(results[0].tags[0]).toEqual('tag1'); + expect(results[0].tags[1]).toEqual('tag2'); }); }); @@ -149,14 +136,14 @@ describe('graphiteDatasource', function() { ctx.ds.annotationQuery(options).then(function(data) { results = data; }); - ctx.$rootScope.$apply(); + // ctx.$rootScope.$apply(); }); it('should parse the tags string into an array', () => { - expect(_.isArray(results[0].tags)).to.eql(true); - expect(results[0].tags.length).to.eql(2); - expect(results[0].tags[0]).to.eql('tag1'); - expect(results[0].tags[1]).to.eql('tag2'); + expect(_.isArray(results[0].tags)).toEqual(true); + expect(results[0].tags.length).toEqual(2); + expect(results[0].tags[0]).toEqual('tag1'); + expect(results[0].tags[1]).toEqual('tag2'); }); }); }); @@ -166,21 +153,21 @@ describe('graphiteDatasource', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{}], }); - expect(results.length).to.be(0); + expect(results.length).toBe(0); }); it('should uri escape targets', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{ target: 'prod1.{test,test2}' }, { target: 'prod2.count' }], }); - expect(results).to.contain('target=prod1.%7Btest%2Ctest2%7D'); + expect(results).toContain('target=prod1.%7Btest%2Ctest2%7D'); }); it('should replace target placeholder', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{ target: 'series1' }, { target: 'series2' }, { target: 'asPercent(#A,#B)' }], }); - expect(results[2]).to.be('target=asPercent(series1%2Cseries2)'); + expect(results[2]).toBe('target=asPercent(series1%2Cseries2)'); }); it('should replace target placeholder for hidden series', function() { @@ -191,35 +178,35 @@ describe('graphiteDatasource', function() { { target: 'asPercent(#A,#B)' }, ], }); - expect(results[0]).to.be('target=' + encodeURIComponent('asPercent(series1,sumSeries(series1))')); + expect(results[0]).toBe('target=' + encodeURIComponent('asPercent(series1,sumSeries(series1))')); }); it('should replace target placeholder when nesting query references', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{ target: 'series1' }, { target: 'sumSeries(#A)' }, { target: 'asPercent(#A,#B)' }], }); - expect(results[2]).to.be('target=' + encodeURIComponent('asPercent(series1,sumSeries(series1))')); + expect(results[2]).toBe('target=' + encodeURIComponent('asPercent(series1,sumSeries(series1))')); }); it('should fix wrong minute interval parameters', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{ target: "summarize(prod.25m.count, '25m', 'sum')" }], }); - expect(results[0]).to.be('target=' + encodeURIComponent("summarize(prod.25m.count, '25min', 'sum')")); + expect(results[0]).toBe('target=' + encodeURIComponent("summarize(prod.25m.count, '25min', 'sum')")); }); it('should fix wrong month interval parameters', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{ target: "summarize(prod.5M.count, '5M', 'sum')" }], }); - expect(results[0]).to.be('target=' + encodeURIComponent("summarize(prod.5M.count, '5mon', 'sum')")); + expect(results[0]).toBe('target=' + encodeURIComponent("summarize(prod.5M.count, '5mon', 'sum')")); }); it('should ignore empty targets', function() { let results = ctx.ds.buildGraphiteParams({ targets: [{ target: 'series1' }, { target: '' }], }); - expect(results.length).to.be(2); + expect(results.length).toBe(2); }); }); @@ -231,7 +218,7 @@ describe('graphiteDatasource', function() { ctx.backendSrv.datasourceRequest = function(options) { requestOptions = options; return ctx.$q.when({ - data: [{ target: 'prod1.count', datapoints: [[10, 1], [12, 1]] }], + data: ['backend_01', 'backend_02'], }); }; }); @@ -241,10 +228,9 @@ describe('graphiteDatasource', function() { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/tags'); - expect(requestOptions.params.expr).to.eql([]); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/tags'); + expect(requestOptions.params.expr).toEqual([]); + expect(results).not.toBe(null); }); it('should generate tags query with a filter expression', () => { @@ -252,21 +238,19 @@ describe('graphiteDatasource', function() { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/tags'); - expect(requestOptions.params.expr).to.eql(['server=backend_01']); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/tags'); + expect(requestOptions.params.expr).toEqual(['server=backend_01']); + expect(results).not.toBe(null); }); - it('should generate tag query for an expression with whitespace after', () => { + it('should generate tags query for an expression with whitespace after', () => { ctx.ds.metricFindQuery('tags(server=backend_01 )').then(data => { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/tags'); - expect(requestOptions.params.expr).to.eql(['server=backend_01']); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/tags'); + expect(requestOptions.params.expr).toEqual(['server=backend_01']); + expect(results).not.toBe(null); }); it('should generate tag values query for one tag', () => { @@ -274,11 +258,10 @@ describe('graphiteDatasource', function() { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/values'); - expect(requestOptions.params.tag).to.be('server'); - expect(requestOptions.params.expr).to.eql([]); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/values'); + expect(requestOptions.params.tag).toBe('server'); + expect(requestOptions.params.expr).toEqual([]); + expect(results).not.toBe(null); }); it('should generate tag values query for a tag and expression', () => { @@ -286,11 +269,10 @@ describe('graphiteDatasource', function() { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/values'); - expect(requestOptions.params.tag).to.be('server'); - expect(requestOptions.params.expr).to.eql(['server=~backend*']); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/values'); + expect(requestOptions.params.tag).toBe('server'); + expect(requestOptions.params.expr).toEqual(['server=~backend*']); + expect(results).not.toBe(null); }); it('should generate tag values query for a tag with whitespace after', () => { @@ -298,11 +280,10 @@ describe('graphiteDatasource', function() { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/values'); - expect(requestOptions.params.tag).to.be('server'); - expect(requestOptions.params.expr).to.eql([]); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/values'); + expect(requestOptions.params.tag).toBe('server'); + expect(requestOptions.params.expr).toEqual([]); + expect(results).not.toBe(null); }); it('should generate tag values query for a tag and expression with whitespace after', () => { @@ -310,11 +291,10 @@ describe('graphiteDatasource', function() { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/tags/autoComplete/values'); - expect(requestOptions.params.tag).to.be('server'); - expect(requestOptions.params.expr).to.eql(['server=~backend*']); - expect(results).not.to.be(null); + expect(requestOptions.url).toBe('/tags/autoComplete/values'); + expect(requestOptions.params.tag).toBe('server'); + expect(requestOptions.params.expr).toEqual(['server=~backend*']); + expect(results).not.toBe(null); }); }); }); From d7f58d74d353bec310467d2dee4976a16b7c335c Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 20 Apr 2018 11:14:33 +0200 Subject: [PATCH 25/27] changelog: adds releaste date for 5.1.0-beta1 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5edc8397412..63ec1965098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 5.1.0 (unreleased) +# 5.1.0-beta1 (2018-04-20) * **MSSQL**: New Microsoft SQL Server data source [#10093](https://github.com/grafana/grafana/pull/10093), [#11298](https://github.com/grafana/grafana/pull/11298), thx [@linuxchips](https://github.com/linuxchips) * **Prometheus**: The heatmap panel now support Prometheus histograms [#10009](https://github.com/grafana/grafana/issues/10009) From 177220e2fe3bc96eb0a34ce9ca47bfdefb589a9e Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 20 Apr 2018 12:59:44 +0200 Subject: [PATCH 26/27] build: fixes release deploy --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e7f40419402..b6514c4cb47 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -117,7 +117,7 @@ jobs: - image: circleci/python:2.7-stretch steps: - attach_workspace: - at: dist + at: . - run: name: install awscli command: 'sudo pip install awscli' From e168bfe03e03afdc4f49fd3d2b20b9ae2ca07f91 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 20 Apr 2018 13:23:45 +0200 Subject: [PATCH 27/27] docs: release 5.1.0-beta1 --- docs/sources/installation/debian.md | 8 ++++++++ docs/sources/installation/rpm.md | 7 +++++++ docs/sources/installation/windows.md | 1 + packaging/publish/publish_testing.sh | 4 ++-- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 8b51a75a826..8b2e15ad124 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -16,6 +16,7 @@ weight = 1 Description | Download ------------ | ------------- Stable for Debian-based Linux | [grafana_5.0.4_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.4_amd64.deb) +Beta for Debian-based Linux | [grafana_5.1.0-beta1_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.1.0-beta1_amd64.deb) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. @@ -29,6 +30,13 @@ sudo apt-get install -y adduser libfontconfig sudo dpkg -i grafana_5.0.4_amd64.deb ``` +## Install Latest Beta +```bash +wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.1.0-beta1_amd64.deb +sudo apt-get install -y adduser libfontconfig +sudo dpkg -i grafana_5.1.0-beta1_amd64.deb +``` + ## APT Repository Add the following line to your `/etc/apt/sources.list` file. diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index 05192512e5a..3650560d5cf 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -16,6 +16,7 @@ weight = 2 Description | Download ------------ | ------------- Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.4 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm) +Latest Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [5.1.0-beta1 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.0-beta1.x86_64.rpm) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing @@ -29,6 +30,12 @@ You can install Grafana using Yum directly. $ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm ``` +## Install Beta + +```bash +$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.0-beta1.x86_64.rpm +``` + Or install manually using `rpm`. #### On CentOS / Fedora / Redhat: diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 4f8d7696b57..31fe243c01d 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -13,6 +13,7 @@ weight = 3 Description | Download ------------ | ------------- Latest stable package for Windows | [grafana-5.0.4.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4.windows-x64.zip) +Latest beta package for Windows | [grafana.5.1.0-beta1.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta5.windows-x64.zip) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. diff --git a/packaging/publish/publish_testing.sh b/packaging/publish/publish_testing.sh index 08ba2a89dd9..9fd4e1f93b9 100755 --- a/packaging/publish/publish_testing.sh +++ b/packaging/publish/publish_testing.sh @@ -1,6 +1,6 @@ #! /usr/bin/env bash -deb_ver=5.0.0-beta5 -rpm_ver=5.0.0-beta5 +deb_ver=5.1.0-beta1 +rpm_ver=5.1.0-beta1 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb