Merge pull request #4786 from influxdata/bugfix/get-protoboards-from-multistore

Get protoboards from multistore if not able to find from ProtoboardsPath
fix/ci-pivot
Deniz Kusefoglu 2018-11-08 17:47:45 -08:00 committed by GitHub
commit bc21a59ec9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 208 additions and 4 deletions

View File

@ -46,7 +46,7 @@ docker: dep assets docker-${BINARY}
assets: .jssrc .bindata
.bindata: server/swagger_gen.go canned/bin_gen.go dist/dist_gen.go
.bindata: server/swagger_gen.go canned/bin_gen.go protoboards/bin_gen.go dist/dist_gen.go
@touch .bindata
dist/dist_gen.go: $(UISOURCES)
@ -57,6 +57,9 @@ server/swagger_gen.go: server/swagger.json
canned/bin_gen.go: canned/*.json
go generate -x ./canned
protoboards/bin_gen.go: protoboards/*.json
go generate -x ./protoboards
.jssrc: $(UISOURCES)
cd ui && yarn run clean && yarn run build
@ -112,7 +115,7 @@ clean:
if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi
cd ui && yarn run clean
cd ui && rm -rf node_modules
rm -f dist/dist_gen.go canned/bin_gen.go server/swagger_gen.go
rm -f dist/dist_gen.go canned/bin_gen.go protoboards/bin_gen.go server/swagger_gen.go
@rm -f .godep .jsdep .jssrc .bindata
ctags:

72
multistore/protoboards.go Normal file
View File

@ -0,0 +1,72 @@
package multistore
import (
"context"
"fmt"
"github.com/influxdata/chronograf"
)
// Protoboards is a ProtoboardsStore that contains multiple ProtoboardsStores
// The All method will return the set of all Protoboards.
// Each method will be tried against the Stores slice serially.
type Protoboards struct {
Stores []chronograf.ProtoboardsStore
}
// All returns the set of all protoboards
func (s *Protoboards) All(ctx context.Context) ([]chronograf.Protoboard, error) {
all := []chronograf.Protoboard{}
protoboardSet := map[string]chronograf.Protoboard{}
ok := false
var err error
for _, store := range s.Stores {
var protoboards []chronograf.Protoboard
protoboards, err = store.All(ctx)
if err != nil {
// Try to load as many protoboards as possible
continue
}
ok = true
for _, l := range protoboards {
// Enforce that the protoboard has a unique ID
// If the protoboard has been seen before then skip
if _, okay := protoboardSet[l.ID]; !okay {
protoboardSet[l.ID] = l
all = append(all, l)
}
}
}
if !ok {
return nil, err
}
return all, nil
}
// Get retrieves protoboard if `ID` exists. Searches through each store sequentially until success.
func (s *Protoboards) Get(ctx context.Context, ID string) (chronograf.Protoboard, error) {
var err error
for _, store := range s.Stores {
var l chronograf.Protoboard
l, err = store.Get(ctx, ID)
if err == nil {
return l, nil
}
}
return chronograf.Protoboard{}, err
}
// Add creates a new protoboard in the protoboardsStore.
func (s *Protoboards) Add(ctx context.Context, protoboard chronograf.Protoboard) (chronograf.Protoboard, error) {
return chronograf.Protoboard{}, fmt.Errorf("Add to multistore/protoboards not supported")
}
// Delete the protoboard from the store.
func (s *Protoboards) Delete(ctx context.Context, protoboard chronograf.Protoboard) error {
return fmt.Errorf("Delete to multistore/protoboards not supported")
}
// Update the protoboard in the store.
func (s *Protoboards) Update(ctx context.Context, protoboard chronograf.Protoboard) error {
return fmt.Errorf("Update to multistore/protoboards not supported")
}

83
protoboards/bin.go Normal file
View File

@ -0,0 +1,83 @@
package protoboards
import (
"context"
"encoding/json"
"fmt"
"github.com/influxdata/chronograf"
)
//go:generate go-bindata -o bin_gen.go -ignore README|apps|.sh|go -pkg protoboards .
// BinProtoboardsStore represents a protoboards store using data generated by go-bindata
type BinProtoboardsStore struct {
Logger chronograf.Logger
}
// All returns the set of all protoboards
func (s *BinProtoboardsStore) All(ctx context.Context) ([]chronograf.Protoboard, error) {
names := AssetNames()
protoboards := make([]chronograf.Protoboard, len(names))
for i, name := range names {
octets, err := Asset(name)
if err != nil {
s.Logger.
WithField("component", "protoboards").
WithField("name", name).
Error("Invalid protoboard: ", err)
return nil, chronograf.ErrProtoboardInvalid
}
var protoboard chronograf.Protoboard
if err = json.Unmarshal(octets, &protoboard); err != nil {
s.Logger.
WithField("component", "protoboards").
WithField("name", name).
Error("Unable to read protoboard:", err)
return nil, chronograf.ErrProtoboardInvalid
}
protoboards[i] = protoboard
}
return protoboards, nil
}
// Add is not support by BinProtoboardsStore
func (s *BinProtoboardsStore) Add(ctx context.Context, protoboard chronograf.Protoboard) (chronograf.Protoboard, error) {
return chronograf.Protoboard{}, fmt.Errorf("Add to BinProtoboardsStore not supported")
}
// Delete is not support by BinProtoboardsStore
func (s *BinProtoboardsStore) Delete(ctx context.Context, protoboard chronograf.Protoboard) error {
return fmt.Errorf("Delete to BinProtoboardsStore not supported")
}
// Get retrieves protoboard if `ID` exists.
func (s *BinProtoboardsStore) Get(ctx context.Context, ID string) (chronograf.Protoboard, error) {
protoboards, err := s.All(ctx)
if err != nil {
s.Logger.
WithField("component", "protoboards").
WithField("name", ID).
Error("Invalid protoboard: ", err)
return chronograf.Protoboard{}, chronograf.ErrProtoboardInvalid
}
for _, protoboard := range protoboards {
if protoboard.ID == ID {
return protoboard, nil
}
}
s.Logger.
WithField("component", "protoboards").
WithField("name", ID).
Error("protoboard not found")
return chronograf.Protoboard{}, chronograf.ErrProtoboardNotFound
}
// Update not supported
func (s *BinProtoboardsStore) Update(ctx context.Context, protoboard chronograf.Protoboard) error {
return fmt.Errorf("Update to BinProtoboardsStore not supported")
}

View File

@ -6,6 +6,7 @@ import (
"github.com/influxdata/chronograf/filestore"
"github.com/influxdata/chronograf/memdb"
"github.com/influxdata/chronograf/multistore"
"github.com/influxdata/chronograf/protoboards"
)
// LayoutBuilder is responsible for building Layouts
@ -43,6 +44,40 @@ func (builder *MultiLayoutBuilder) Build(db chronograf.LayoutsStore) (*multistor
return layouts, nil
}
// ProtoboardsBuilder is responsible for building Protoboards
type ProtoboardsBuilder interface {
Build() (*multistore.Protoboards, error)
}
// MultiProtoboardsBuilder implements LayoutBuilder and will return a Layouts
type MultiProtoboardsBuilder struct {
Logger chronograf.Logger
UUID chronograf.ID
ProtoboardsPath string
}
// Build will construct a Layouts of canned and db-backed personalized
// layouts
func (builder *MultiProtoboardsBuilder) Build() (*multistore.Protoboards, error) {
// These apps are those handled from a directory
filesystemPBs := filestore.NewProtoboards(builder.ProtoboardsPath, builder.UUID, builder.Logger)
// These apps are statically compiled into chronograf
binPBs := &protoboards.BinProtoboardsStore{
Logger: builder.Logger,
}
// Acts as a front-end to both the bolt layouts, filesystem layouts and binary statically compiled layouts.
// The idea here is that these stores form a hierarchy in which each is tried sequentially until
// the operation has success. So, the database is preferred over filesystem over binary data.
protoboards := &multistore.Protoboards{
Stores: []chronograf.ProtoboardsStore{
filesystemPBs,
binPBs,
},
}
return protoboards, nil
}
// DashboardBuilder is responsible for building dashboards
type DashboardBuilder interface {
Build(chronograf.DashboardsStore) (*multistore.DashboardsStore, error)

View File

@ -18,7 +18,6 @@ import (
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/bolt"
"github.com/influxdata/chronograf/filestore"
idgen "github.com/influxdata/chronograf/id"
"github.com/influxdata/chronograf/influx"
clog "github.com/influxdata/chronograf/log"
@ -286,6 +285,7 @@ type builders struct {
Kapacitors KapacitorBuilder
Dashboards DashboardBuilder
Organizations OrganizationBuilder
Protoboards ProtoboardsBuilder
}
func (s *Server) newBuilders(logger chronograf.Logger) builders {
@ -320,6 +320,11 @@ func (s *Server) newBuilders(logger chronograf.Logger) builders {
Logger: logger,
Path: s.ResourcesPath,
},
Protoboards: &MultiProtoboardsBuilder{
Logger: logger,
UUID: &idgen.UUID{},
ProtoboardsPath: s.ProtoboardsPath,
},
}
}
@ -488,7 +493,13 @@ func openService(ctx context.Context, buildInfo chronograf.BuildInfo, boltPath s
os.Exit(1)
}
protoboards := filestore.NewProtoboards(protoboardsPath, idgen.NewTime(), logger)
protoboards, err := builder.Protoboards.Build()
if err != nil {
logger.
WithField("component", "LayoutsStore").
Error("Unable to construct a MultiLayoutsStore", err)
os.Exit(1)
}
return Service{
TimeSeriesClient: &InfluxClient{},