From 3898ea02e60c2811feec65e8ed4c32fea862b632 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 22 Mar 2018 02:22:58 +0100 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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, }