Update annotations to use time as endTime
parent
11121e1ac5
commit
5731d3f059
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue