2017-12-15 03:01:07 +00:00
package filestore
2016-10-10 15:45:35 +00:00
import (
2016-10-25 15:20:06 +00:00
"context"
2016-10-10 15:45:35 +00:00
"encoding/json"
"io/ioutil"
"os"
"path"
2016-10-20 14:38:23 +00:00
"github.com/influxdata/chronograf"
2016-10-10 15:45:35 +00:00
)
2017-03-06 16:11:52 +00:00
// AppExt is the the file extension searched for in the directory for layout files
2016-10-10 15:45:35 +00:00
const AppExt = ".json"
2020-01-16 21:09:56 +00:00
// Verify apps (layouts) implements layoutsStore interface.
var _ chronograf . LayoutsStore = ( * Apps ) ( nil )
2017-10-24 22:50:11 +00:00
// Apps are canned JSON layouts. Implements LayoutsStore.
2016-10-10 15:45:35 +00:00
type Apps struct {
2020-01-16 21:09:56 +00:00
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
2016-10-10 15:45:35 +00:00
}
2017-03-06 16:11:52 +00:00
// NewApps constructs a layout store wrapping a file system directory
2017-10-24 22:50:11 +00:00
func NewApps ( dir string , ids chronograf . ID , logger chronograf . Logger ) chronograf . LayoutsStore {
2016-10-10 15:45:35 +00:00
return & Apps {
2020-01-16 21:09:56 +00:00
Dir : dir ,
Load : loadFile ,
ReadDir : ioutil . ReadDir ,
IDs : ids ,
Logger : logger ,
2016-10-10 15:45:35 +00:00
}
}
2016-10-20 14:38:23 +00:00
func loadFile ( name string ) ( chronograf . Layout , error ) {
2016-10-10 15:45:35 +00:00
octets , err := ioutil . ReadFile ( name )
if err != nil {
2016-11-07 16:10:26 +00:00
return chronograf . Layout { } , chronograf . ErrLayoutNotFound
2016-10-10 15:45:35 +00:00
}
2020-01-16 21:09:56 +00:00
2016-10-20 14:38:23 +00:00
var layout chronograf . Layout
2016-10-10 15:45:35 +00:00
if err = json . Unmarshal ( octets , & layout ) ; err != nil {
2016-11-07 16:10:26 +00:00
return chronograf . Layout { } , chronograf . ErrLayoutInvalid
2016-10-10 15:45:35 +00:00
}
2017-03-06 16:11:52 +00:00
2020-01-16 21:09:56 +00:00
return layout , nil
2016-10-10 15:45:35 +00:00
}
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 ) {
2016-10-10 15:45:35 +00:00
files , err := a . ReadDir ( a . Dir )
if err != nil {
return nil , err
}
2016-10-20 14:38:23 +00:00
layouts := [ ] chronograf . Layout { }
2016-10-10 15:45:35 +00:00
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 {
2016-10-10 15:45:35 +00:00
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 ) {
2016-11-07 16:10:26 +00:00
l , file , err := a . idToFile ( ID )
2016-10-11 17:52:16 +00:00
if err != nil {
2016-10-20 14:38:23 +00:00
return chronograf . Layout { } , err
2016-10-11 17:52:16 +00:00
}
2016-11-07 16:10:26 +00:00
2016-10-10 15:45:35 +00:00
if err != nil {
2016-11-07 16:10:26 +00:00
if err == chronograf . ErrLayoutNotFound {
2016-11-07 16:27:35 +00:00
a . Logger .
2016-11-07 16:10:26 +00:00
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 .
2016-11-07 16:10:26 +00:00
WithField ( "component" , "apps" ) .
WithField ( "name" , file ) .
Error ( "File is not a layout" )
}
return chronograf . Layout { } , err
2016-10-10 15:45:35 +00:00
}
return l , nil
}
2016-10-11 17:52:16 +00:00
// idToFile takes an id and finds the associated filename
2016-11-07 16:10:26 +00:00
func ( a * Apps ) idToFile ( ID string ) ( chronograf . Layout , string , error ) {
2016-10-11 17:52:16 +00:00
// Because the entire layout information is not known at this point, we need
2016-11-07 16:10:26 +00:00
// to try to find the name of the file through matching the ID in the layout
// content with the ID passed.
2016-10-11 17:52:16 +00:00
files , err := a . ReadDir ( a . Dir )
if err != nil {
2016-11-07 16:10:26 +00:00
return chronograf . Layout { } , "" , err
2016-10-11 17:52:16 +00:00
}
for _ , f := range files {
2016-11-07 16:10:26 +00:00
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
2016-10-11 17:52:16 +00:00
}
}
2016-11-07 16:10:26 +00:00
return chronograf . Layout { } , "" , chronograf . ErrLayoutNotFound
2016-10-11 17:52:16 +00:00
}