chronograf/filestore/apps.go

124 lines
3.3 KiB
Go
Raw Normal View History

package filestore
import (
2016-10-25 15:20:06 +00:00
"context"
"encoding/json"
"io/ioutil"
"os"
"path"
2016-10-20 14:38:23 +00:00
"github.com/influxdata/chronograf"
)
2017-03-06 16:11:52 +00:00
// AppExt is the the file extension searched for in the directory for layout files
const AppExt = ".json"
// Verify apps (layouts) implements layoutsStore interface.
var _ chronograf.LayoutsStore = (*Apps)(nil)
// Apps are canned JSON layouts. Implements LayoutsStore.
type Apps struct {
Dir string // Dir is the directory contained the pre-canned applications.
Load func(string) (chronograf.Layout, error) // Load loads string name and return a Layout
ReadDir func(dirname string) ([]os.FileInfo, error) // ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
IDs chronograf.ID // IDs generate unique ids for new application layouts
Logger chronograf.Logger
}
2017-03-06 16:11:52 +00:00
// NewApps constructs a layout store wrapping a file system directory
func NewApps(dir string, ids chronograf.ID, logger chronograf.Logger) chronograf.LayoutsStore {
return &Apps{
Dir: dir,
Load: loadFile,
ReadDir: ioutil.ReadDir,
IDs: ids,
Logger: logger,
}
}
2016-10-20 14:38:23 +00:00
func loadFile(name string) (chronograf.Layout, error) {
octets, err := ioutil.ReadFile(name)
if err != nil {
return chronograf.Layout{}, chronograf.ErrLayoutNotFound
}
2016-10-20 14:38:23 +00:00
var layout chronograf.Layout
if err = json.Unmarshal(octets, &layout); err != nil {
return chronograf.Layout{}, chronograf.ErrLayoutInvalid
}
2017-03-06 16:11:52 +00:00
return layout, nil
}
2017-03-06 16:11:52 +00:00
// All returns all layouts from the directory
2016-10-20 14:38:23 +00:00
func (a *Apps) All(ctx context.Context) ([]chronograf.Layout, error) {
files, err := a.ReadDir(a.Dir)
if err != nil {
return nil, err
}
2016-10-20 14:38:23 +00:00
layouts := []chronograf.Layout{}
for _, file := range files {
if path.Ext(file.Name()) != AppExt {
continue
}
2016-10-11 00:34:05 +00:00
if layout, err := a.Load(path.Join(a.Dir, file.Name())); err != nil {
continue // We want to load all files we can.
} else {
layouts = append(layouts, layout)
}
}
return layouts, nil
}
2017-03-06 16:11:52 +00:00
// Get returns an app file from the layout directory
2016-10-20 14:38:23 +00:00
func (a *Apps) Get(ctx context.Context, ID string) (chronograf.Layout, error) {
l, file, err := a.idToFile(ID)
if err != nil {
2016-10-20 14:38:23 +00:00
return chronograf.Layout{}, err
}
if err != nil {
if err == chronograf.ErrLayoutNotFound {
2016-11-07 16:27:35 +00:00
a.Logger.
WithField("component", "apps").
WithField("name", file).
Error("Unable to read file")
} else if err == chronograf.ErrLayoutInvalid {
2016-11-07 16:27:35 +00:00
a.Logger.
WithField("component", "apps").
WithField("name", file).
Error("File is not a layout")
}
return chronograf.Layout{}, err
}
return l, nil
}
// idToFile takes an id and finds the associated filename
func (a *Apps) idToFile(ID string) (chronograf.Layout, string, error) {
// Because the entire layout information is not known at this point, we need
// to try to find the name of the file through matching the ID in the layout
// content with the ID passed.
files, err := a.ReadDir(a.Dir)
if err != nil {
return chronograf.Layout{}, "", err
}
for _, f := range files {
if path.Ext(f.Name()) != AppExt {
continue
}
file := path.Join(a.Dir, f.Name())
layout, err := a.Load(file)
if err != nil {
return chronograf.Layout{}, "", err
}
if layout.ID == ID {
return layout, file, nil
}
}
return chronograf.Layout{}, "", chronograf.ErrLayoutNotFound
}