chronograf/influx/annotations.go

173 lines
4.9 KiB
Go
Raw Normal View History

2018-01-09 23:15:12 +00:00
package influx
import (
"context"
"encoding/json"
"fmt"
"github.com/influxdata/chronograf"
)
const (
// AllAnnotations returns all annotations from the chronograf database
AllAnnotations = `SELECT "duration_ns", "text", "type", "name" FROM "chronograf"."autogen"."annotations" WHERE "deleted"=false ORDER BY time DESC`
2018-01-09 23:15:12 +00:00
// GetAnnotationID returns all annotations from the chronograf database where id is %s
GetAnnotationID = `SELECT "duration_ns", "text", "type", "name" FROM "chronograf"."autogen"."annotations" WHERE "name"='%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
DefaultRP = "autogen"
// DefaultMeasurement is annotations.
DefaultMeasurement = "annotations"
2018-01-09 23:15:12 +00:00
)
2018-01-12 23:17:14 +00:00
var _ chronograf.AnnotationStore = &AnnotationStore{}
2018-01-09 23:15:12 +00:00
// AnnotationStore stores annotations within InfluxDB
type AnnotationStore struct {
2018-01-12 23:17:14 +00:00
client chronograf.TimeSeries
}
// NewAnnotationStore constructs an annoation store with a client
func NewAnnotationStore(client chronograf.TimeSeries) *AnnotationStore {
return &AnnotationStore{
client: client,
}
2018-01-09 23:15:12 +00:00
}
// All lists all Annotations
func (a *AnnotationStore) All(ctx context.Context) ([]chronograf.Annotation, error) {
2018-01-12 23:17:14 +00:00
return a.allAnnotations(ctx)
2018-01-09 23:15:12 +00:00
}
// Get retrieves an annotation
func (a *AnnotationStore) Get(ctx context.Context, id string) (chronograf.Annotation, error) {
2018-01-12 23:17:14 +00:00
annos, err := a.getAnnotations(ctx, id)
2018-01-09 23:15:12 +00:00
if err != nil {
return chronograf.Annotation{}, err
}
if len(annos) == 0 {
// TODO: change this to a chronograf.Error
return chronograf.Annotation{}, fmt.Errorf("Unknown annotation id %s", id)
}
return annos[0], nil
}
// Add creates a new annotation in the store
func (a *AnnotationStore) Add(ctx context.Context, anno chronograf.Annotation) (chronograf.Annotation, error) {
2018-01-12 23:17:14 +00:00
return anno, a.client.Write(ctx, &chronograf.Point{
Database: DefaultDB,
RetentionPolicy: DefaultRP,
})
2018-01-09 23:15:12 +00:00
}
// Delete removes the annotation from the store
func (a *AnnotationStore) Delete(ctx context.Context, anno chronograf.Annotation) error {
2018-01-12 23:17:14 +00:00
return a.client.Write(ctx, &chronograf.Point{
Database: DefaultDB,
RetentionPolicy: DefaultRP,
})
2018-01-09 23:15:12 +00:00
}
// Update replaces annotation (just a call through to Add)
func (a *AnnotationStore) Update(ctx context.Context, anno chronograf.Annotation) error {
_, err := a.Add(ctx, anno)
return err
2018-01-09 23:15:12 +00:00
}
type value []interface{}
func (v value) Int64(idx int) (int64, error) {
if idx >= len(v) {
return 0, fmt.Errorf("index %d does not exist in values", idx)
}
i, ok := v[idx].(int64)
if !ok {
return 0, fmt.Errorf("value at index %d is not int64, but, %T", idx, v[idx])
}
return i, nil
}
func (v value) String(idx int) (string, error) {
if idx >= len(v) {
return "", fmt.Errorf("index %d does not exist in values", idx)
}
str, ok := v[idx].(string)
if !ok {
return "", fmt.Errorf("value at index %d is not string, but, %T", idx, v[idx])
}
return str, nil
}
type annotationResults []struct {
Series []struct {
Values []value `json:"values"`
} `json:"series"`
}
// Annotations converts `SELECT "duration_ns", "text", "type", "name" FROM "chronograf"."autogen"."annotations"` to annotations
2018-01-09 23:15:12 +00:00
func (r *annotationResults) Annotations() (res []chronograf.Annotation, err error) {
res = []chronograf.Annotation{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
anno := chronograf.Annotation{}
if anno.Time, err = v.Int64(0); err != nil {
return
}
if anno.Duration, err = v.Int64(1); err != nil {
return
}
if anno.Text, err = v.String(2); err != nil {
return
}
if anno.Type, err = v.String(3); err != nil {
return
}
if anno.Name, err = v.String(4); err != nil {
return
}
res = append(res, anno)
}
}
}
return res, err
}
// queryAnnotations queries the chronograf db and produces all annotations
2018-01-12 23:17:14 +00:00
func (a *AnnotationStore) queryAnnotations(ctx context.Context, query string) ([]chronograf.Annotation, error) {
res, err := a.client.Query(ctx, chronograf.Query{
2018-01-09 23:15:12 +00:00
Command: query,
2018-01-12 05:05:23 +00:00
DB: DefaultDB,
Epoch: "ns",
2018-01-09 23:15:12 +00:00
})
if err != nil {
return nil, err
}
octets, err := res.MarshalJSON()
if err != nil {
return nil, err
}
results := annotationResults{}
if err := json.Unmarshal(octets, &results); err != nil {
return nil, err
}
return results.Annotations()
}
// allAnnotations returns all annotations from the chronograf.annotations measurement
2018-01-12 23:17:14 +00:00
func (a *AnnotationStore) allAnnotations(ctx context.Context) ([]chronograf.Annotation, error) {
2018-01-09 23:15:12 +00:00
// TODO: dedup all ids
2018-01-12 23:17:14 +00:00
return a.queryAnnotations(ctx, AllAnnotations)
2018-01-09 23:15:12 +00:00
}
// getAnnotations returns all annotations with id
2018-01-12 23:17:14 +00:00
func (a *AnnotationStore) getAnnotations(ctx context.Context, id string) ([]chronograf.Annotation, error) {
return a.queryAnnotations(ctx, fmt.Sprintf(GetAnnotationID, id))
2018-01-09 23:15:12 +00:00
}