From 5731d3f059961bb8c2b7ff0832eeab15c6e8f67c Mon Sep 17 00:00:00 2001 From: Chris Goller Date: Thu, 25 Jan 2018 14:36:28 -0800 Subject: [PATCH] Update annotations to use time as endTime --- chronograf.go | 10 ++--- influx/annotations.go | 26 ++++-------- server/annotations.go | 99 +++++++++++++++++++------------------------ 3 files changed, 57 insertions(+), 78 deletions(-) diff --git a/chronograf.go b/chronograf.go index b242ed20ad..7416b8e126 100644 --- a/chronograf.go +++ b/chronograf.go @@ -487,11 +487,11 @@ type Databases interface { // Annotation represents a time-based metadata associated with a source type Annotation struct { - ID string // ID is the unique annotation identifier - Time time.Time // Time is the start time of the annotation - Duration time.Duration // Duration of the annotation - Text string // Text is the associated user-facing text describing the annotation - Type string // Type describes the kind of annotation + ID string // ID is the unique annotation identifier + StartTime time.Time // StartTime starts the annotation + EndTime time.Time // EndTime ends the annotation + Text string // Text is the associated user-facing text describing the annotation + Type string // Type describes the kind of annotation } // AnnotationStore represents storage and retrieval of annotations diff --git a/influx/annotations.go b/influx/annotations.go index 26f3e141e1..8332be28ea 100644 --- a/influx/annotations.go +++ b/influx/annotations.go @@ -14,9 +14,9 @@ import ( const ( // AllAnnotations returns all annotations from the chronograf database - AllAnnotations = `SELECT "duration_ns", "modified_time_ns", "text", "type", "id" FROM "chronograf"."autogen"."annotations" WHERE "deleted"=false AND time > %dns and time < %dns ORDER BY time DESC` + AllAnnotations = `SELECT "start_time", "modified_time_ns", "text", "type", "id" FROM "chronograf"."autogen"."annotations" WHERE "deleted"=false AND time > %dns and start_time < %dns ORDER BY time DESC` // GetAnnotationID returns all annotations from the chronograf database where id is %s - GetAnnotationID = `SELECT "duration_ns", "modified_time_ns", "text", "type", "id" FROM "chronograf"."autogen"."annotations" WHERE "id"='%s' AND "deleted"=false ORDER BY time DESC` + GetAnnotationID = `SELECT "start_time", "modified_time_ns", "text", "type", "id" FROM "chronograf"."autogen"."annotations" WHERE "id"='%s' AND "deleted"=false ORDER BY time DESC` // DefaultDB is chronograf. Perhaps later we allow this to be changed DefaultDB = "chronograf" // DefaultRP is autogen. Perhaps later we allow this to be changed @@ -91,7 +91,7 @@ func (a *AnnotationStore) Update(ctx context.Context, anno *chronograf.Annotatio // If the updated annotation has a different time, then, we must // delete the previous annotation - if cur.Time != anno.Time { + if cur.EndTime != anno.EndTime { return a.client.Write(ctx, toDeletedPoint(cur)) } return nil @@ -126,13 +126,13 @@ func toPoint(anno *chronograf.Annotation) *chronograf.Point { Database: DefaultDB, RetentionPolicy: DefaultRP, Measurement: DefaultMeasurement, - Time: anno.Time.UnixNano(), + Time: anno.EndTime.UnixNano(), Tags: map[string]string{ "id": anno.ID, }, Fields: map[string]interface{}{ "deleted": false, - "duration_ns": int64(anno.Duration), + "start_time": anno.StartTime.UnixNano(), "modified_time_ns": int64(time.Now().UnixNano()), "text": anno.Text, "type": anno.Type, @@ -145,13 +145,13 @@ func toDeletedPoint(anno *chronograf.Annotation) *chronograf.Point { Database: DefaultDB, RetentionPolicy: DefaultRP, Measurement: DefaultMeasurement, - Time: anno.Time.UnixNano(), + Time: anno.EndTime.UnixNano(), Tags: map[string]string{ "id": anno.ID, }, Fields: map[string]interface{}{ "deleted": true, - "duration_ns": 0, + "start_time": int64(0), "modified_time_ns": int64(time.Now().UnixNano()), "text": "", "type": "", @@ -180,14 +180,6 @@ func (v value) Time(idx int) (time.Time, error) { return time.Unix(0, tm), nil } -func (v value) Duration(idx int) (time.Duration, error) { - dur, err := v.Int64(idx) - if err != nil { - return 0, err - } - return time.Duration(dur), nil -} - func (v value) String(idx int) (string, error) { if idx >= len(v) { return "", fmt.Errorf("index %d does not exist in values", idx) @@ -222,11 +214,11 @@ func (r *influxResults) Annotations() (res []chronograf.Annotation, err error) { for _, v := range s.Values { anno := annotationResult{} - if anno.Time, err = v.Time(0); err != nil { + if anno.EndTime, err = v.Time(0); err != nil { return } - if anno.Duration, err = v.Duration(1); err != nil { + if anno.StartTime, err = v.Time(1); err != nil { return } diff --git a/server/annotations.go b/server/annotations.go index bb72f9d040..d7c57707ba 100644 --- a/server/annotations.go +++ b/server/annotations.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "net/url" - "strconv" "time" "github.com/influxdata/chronograf" @@ -23,22 +22,22 @@ type annotationLinks struct { } type annotationResponse struct { - ID string `json:"id"` // ID is the unique annotation identifier - Time string `json:"time"` // Time in RFC3339 of the start of the annotation - Duration string `json:"duration"` // Duration is the duration in milliseconds of the annotation - Text string `json:"text"` // Text is the associated user-facing text describing the annotation - Type string `json:"type"` // Type describes the kind of annotation - Links annotationLinks `json:"links"` + ID string `json:"id"` // ID is the unique annotation identifier + StartTime string `json:"startTime"` // StartTime in RFC3339 of the start of the annotation + EndTime string `json:"endTime"` // EndTime in RFC3339 of the end of the annotation + Text string `json:"text"` // Text is the associated user-facing text describing the annotation + Type string `json:"type"` // Type describes the kind of annotation + Links annotationLinks `json:"links"` } func newAnnotationResponse(src chronograf.Source, a *chronograf.Annotation) annotationResponse { base := "/chronograf/v1/sources" return annotationResponse{ - ID: a.ID, - Time: a.Time.Format(timeMilliFormat), - Duration: fmt.Sprintf("%d", int64(a.Duration/time.Millisecond)), - Text: a.Text, - Type: a.Type, + ID: a.ID, + StartTime: a.StartTime.Format(timeMilliFormat), + EndTime: a.EndTime.Format(timeMilliFormat), + Text: a.Text, + Type: a.Type, Links: annotationLinks{ Self: fmt.Sprintf("%s/%d/annotations/%s", base, src.ID, a.ID), }, @@ -178,17 +177,17 @@ func (s *Service) Annotation(w http.ResponseWriter, r *http.Request) { } type newAnnotationRequest struct { - Time time.Time `json:"time"` // Time is the time in rfc3339 milliseconds - Duration time.Duration `json:"duration"` // Duration is the annotation duration in milliseconds - Text string `json:"text,omitempty"` // Text is the associated user-facing text describing the annotation - Type string `json:"type,omitempty"` // Type describes the kind of annotation + StartTime time.Time `json:"startTime"` // StartTime is the time in rfc3339 milliseconds + EndTime time.Time `json:"endTime"` // EndTime is the time in rfc3339 milliseconds + Text string `json:"text,omitempty"` // Text is the associated user-facing text describing the annotation + Type string `json:"type,omitempty"` // Type describes the kind of annotation } func (ar *newAnnotationRequest) UnmarshalJSON(data []byte) error { type Alias newAnnotationRequest aux := &struct { - Time string `json:"time"` - Duration string `json:"duration"` + StartTime string `json:"startTime"` + EndTime string `json:"endTime"` *Alias }{ Alias: (*Alias)(ar), @@ -198,21 +197,14 @@ func (ar *newAnnotationRequest) UnmarshalJSON(data []byte) error { } var err error - ar.Time, err = time.Parse(timeMilliFormat, aux.Time) + ar.StartTime, err = time.Parse(timeMilliFormat, aux.StartTime) if err != nil { return err } - if aux.Duration != "" { - // duration in milliseconds is a max of 13 characters - if len(aux.Duration) > 13 { - return fmt.Errorf("duration must be in milliseconds since unix epoch") - } - d, err := strconv.ParseInt(aux.Duration, 10, 64) - if err != nil { - return err - } - ar.Duration = time.Duration(d) * time.Millisecond + ar.EndTime, err = time.Parse(timeMilliFormat, aux.EndTime) + if err != nil { + return err } return nil @@ -220,10 +212,10 @@ func (ar *newAnnotationRequest) UnmarshalJSON(data []byte) error { func (ar *newAnnotationRequest) Annotation() *chronograf.Annotation { return &chronograf.Annotation{ - Time: ar.Time, - Duration: ar.Duration, - Text: ar.Text, - Type: ar.Type, + StartTime: ar.StartTime, + EndTime: ar.EndTime, + Text: ar.Text, + Type: ar.Type, } } @@ -327,17 +319,17 @@ func (s *Service) RemoveAnnotation(w http.ResponseWriter, r *http.Request) { } type updateAnnotationRequest struct { - Time *time.Time `json:"time,omitempty"` // Time is the time in rfc3339 milliseconds - Duration *time.Duration `json:"duration,omitempty"` // Duration is the annotation duration in milliseconds - Text *string `json:"text,omitempty"` // Text is the associated user-facing text describing the annotation - Type *string `json:"type,omitempty"` // Type describes the kind of annotation + StartTime *time.Time `json:"startTime,omitempty"` // StartTime is the time in rfc3339 milliseconds + EndTime *time.Time `json:"endTime,omitempty"` // EndTime is the time in rfc3339 milliseconds + Text *string `json:"text,omitempty"` // Text is the associated user-facing text describing the annotation + Type *string `json:"type,omitempty"` // Type describes the kind of annotation } func (u *updateAnnotationRequest) UnmarshalJSON(data []byte) error { type Alias updateAnnotationRequest aux := &struct { - Time *string `json:"time,omitempty"` - Duration *string `json:"duration,omitempty"` + StartTime *string `json:"startTime,omitempty"` + EndTime *string `json:"endTime,omitempty"` *Alias }{ Alias: (*Alias)(u), @@ -346,29 +338,24 @@ func (u *updateAnnotationRequest) UnmarshalJSON(data []byte) error { return err } - if aux.Time != nil { - tm, err := time.Parse(timeMilliFormat, *aux.Time) + if aux.StartTime != nil { + tm, err := time.Parse(timeMilliFormat, *aux.StartTime) if err != nil { return err } - u.Time = &tm + u.StartTime = &tm } - if aux.Duration != nil { - // duration in milliseconds is a max of 13 characters - if len(*aux.Duration) > 13 { - return fmt.Errorf("duration must be in milliseconds since unix epoch") - } - d, err := strconv.ParseInt(*aux.Duration, 10, 64) + if aux.EndTime != nil { + tm, err := time.Parse(timeMilliFormat, *aux.EndTime) if err != nil { return err } - dur := time.Duration(d) * time.Millisecond - u.Duration = &dur + u.EndTime = &tm } // Update must have at least one field set - if u.Time == nil && u.Duration == nil && u.Text == nil && u.Type == nil { + if u.StartTime == nil && u.EndTime == nil && u.Text == nil && u.Type == nil { return fmt.Errorf("update request must have at least one field") } @@ -422,15 +409,15 @@ func (s *Service) UpdateAnnotation(w http.ResponseWriter, r *http.Request) { return } - if req.Duration != nil { - cur.Duration = *req.Duration + if req.StartTime != nil { + cur.StartTime = *req.StartTime + } + if req.EndTime != nil { + cur.EndTime = *req.EndTime } if req.Text != nil { cur.Text = *req.Text } - if req.Time != nil { - cur.Time = *req.Time - } if req.Type != nil { cur.Type = *req.Type }