Merge pull request #2593 from influxdata/feature/dashboard-filestore
Add filesystem backed dashboard and organization storespull/10616/head
commit
ce45f13cdc
|
@ -1,9 +1,12 @@
|
|||
## v1.4.0.0-beta2 [unreleased]
|
||||
### Features
|
||||
1. [#2593](https://github.com/influxdata/chronograf/pull/2593): Add option to use files for dashboards, organizations, data sources, and kapacitors
|
||||
|
||||
### UI Improvements
|
||||
1. [#2502](https://github.com/influxdata/chronograf/pull/2502): Fix cursor flashing between default and pointer
|
||||
|
||||
### Bug Fixes
|
||||
1. [#2528](https://github.com/influxdata/chronograf/pull/2528): Fix template rendering to ignore template if not in query
|
||||
1. [#2528](https://github.com/influxdata/chronograf/pull/2528): Fix template rendering to ignore template if not in query
|
||||
1. [#2563](https://github.com/influxdata/chronograf/pull/2563): Fix graph inversion if user input y-axis min greater than max
|
||||
1. [#2616](https://github.com/influxdata/chronograf/pull/2616): Fix cell editing so query data choices are kept when updating a cell
|
||||
|
||||
|
|
4
Makefile
4
Makefile
|
@ -93,10 +93,10 @@ internal.pb.go: bolt/internal/internal.proto
|
|||
test: jstest gotest gotestrace
|
||||
|
||||
gotest:
|
||||
go test `go list ./... | grep -v /vendor/`
|
||||
go test ./...
|
||||
|
||||
gotestrace:
|
||||
go test -race `go list ./... | grep -v /vendor/`
|
||||
go test -race ./...
|
||||
|
||||
jstest:
|
||||
cd ui && yarn test
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/uuid"
|
||||
"github.com/influxdata/chronograf/id"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -51,11 +51,11 @@ func NewClient() *Client {
|
|||
c.ServersStore = &ServersStore{client: c}
|
||||
c.LayoutsStore = &LayoutsStore{
|
||||
client: c,
|
||||
IDs: &uuid.V4{},
|
||||
IDs: &id.UUID{},
|
||||
}
|
||||
c.DashboardsStore = &DashboardsStore{
|
||||
client: c,
|
||||
IDs: &uuid.V4{},
|
||||
IDs: &id.UUID{},
|
||||
}
|
||||
c.UsersStore = &UsersStore{client: c}
|
||||
c.OrganizationsStore = &OrganizationsStore{client: c}
|
||||
|
|
|
@ -2,7 +2,6 @@ package bolt
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
|
@ -64,11 +63,9 @@ func (d *DashboardsStore) Migrate(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
defaultOrgID := fmt.Sprintf("%d", defaultOrg.ID)
|
||||
|
||||
for _, board := range boards {
|
||||
if board.Organization == "" {
|
||||
board.Organization = defaultOrgID
|
||||
board.Organization = defaultOrg.ID
|
||||
if err := d.Update(ctx, board); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: internal.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package internal is a generated protocol buffer package.
|
||||
|
@ -1024,7 +1025,7 @@ func (m *Role) GetName() string {
|
|||
}
|
||||
|
||||
type Organization struct {
|
||||
ID uint64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
|
||||
DefaultRole string `protobuf:"bytes,3,opt,name=DefaultRole,proto3" json:"DefaultRole,omitempty"`
|
||||
Public bool `protobuf:"varint,4,opt,name=Public,proto3" json:"Public,omitempty"`
|
||||
|
@ -1035,11 +1036,11 @@ func (m *Organization) String() string { return proto.CompactTextStri
|
|||
func (*Organization) ProtoMessage() {}
|
||||
func (*Organization) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{17} }
|
||||
|
||||
func (m *Organization) GetID() uint64 {
|
||||
func (m *Organization) GetID() string {
|
||||
if m != nil {
|
||||
return m.ID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Organization) GetName() string {
|
||||
|
@ -1146,89 +1147,89 @@ func init() {
|
|||
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
||||
|
||||
var fileDescriptorInternal = []byte{
|
||||
// 1338 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x8e, 0xe3, 0xc4,
|
||||
0x13, 0x97, 0xe3, 0x38, 0xb1, 0x2b, 0xb3, 0xfb, 0x5f, 0xf9, 0xbf, 0x62, 0xcd, 0x22, 0xa1, 0x60,
|
||||
0x81, 0x08, 0x82, 0x1d, 0xd0, 0xac, 0x90, 0x10, 0x02, 0xa4, 0xcc, 0x04, 0x2d, 0xc3, 0x7e, 0xcd,
|
||||
0x76, 0x76, 0x86, 0x13, 0x5a, 0x75, 0x9c, 0x4a, 0x62, 0xad, 0x63, 0x9b, 0xb6, 0x3d, 0x13, 0xf3,
|
||||
0x30, 0x48, 0x48, 0x3c, 0x01, 0xe2, 0xce, 0x15, 0x71, 0xe5, 0x1d, 0x78, 0x05, 0xae, 0xa8, 0xba,
|
||||
0xdb, 0x1f, 0x99, 0x09, 0xab, 0x39, 0x20, 0x6e, 0xfd, 0xab, 0x6a, 0x57, 0xd7, 0xc7, 0xaf, 0xaa,
|
||||
0xdb, 0x70, 0x33, 0x8c, 0x73, 0x14, 0x31, 0x8f, 0xf6, 0x53, 0x91, 0xe4, 0x89, 0x6b, 0x57, 0xd8,
|
||||
0xff, 0xb3, 0x03, 0xbd, 0x69, 0x52, 0x88, 0x00, 0xdd, 0x9b, 0xd0, 0x39, 0x9e, 0x78, 0xc6, 0xd0,
|
||||
0x18, 0x99, 0xac, 0x73, 0x3c, 0x71, 0x5d, 0xe8, 0x3e, 0xe1, 0x6b, 0xf4, 0x3a, 0x43, 0x63, 0xe4,
|
||||
0x30, 0xb9, 0x26, 0xd9, 0xf3, 0x32, 0x45, 0xcf, 0x54, 0x32, 0x5a, 0xbb, 0x77, 0xc1, 0x3e, 0xcd,
|
||||
0xc8, 0xda, 0x1a, 0xbd, 0xae, 0x94, 0xd7, 0x98, 0x74, 0x27, 0x3c, 0xcb, 0x2e, 0x12, 0x31, 0xf7,
|
||||
0x2c, 0xa5, 0xab, 0xb0, 0x7b, 0x0b, 0xcc, 0x53, 0xf6, 0xc8, 0xeb, 0x49, 0x31, 0x2d, 0x5d, 0x0f,
|
||||
0xfa, 0x13, 0x5c, 0xf0, 0x22, 0xca, 0xbd, 0xfe, 0xd0, 0x18, 0xd9, 0xac, 0x82, 0x64, 0xe7, 0x39,
|
||||
0x46, 0xb8, 0x14, 0x7c, 0xe1, 0xd9, 0xca, 0x4e, 0x85, 0xdd, 0x7d, 0x70, 0x8f, 0xe3, 0x0c, 0x83,
|
||||
0x42, 0xe0, 0xf4, 0x65, 0x98, 0x9e, 0xa1, 0x08, 0x17, 0xa5, 0xe7, 0x48, 0x03, 0x3b, 0x34, 0x74,
|
||||
0xca, 0x63, 0xcc, 0x39, 0x9d, 0x0d, 0xd2, 0x54, 0x05, 0x5d, 0x1f, 0xf6, 0xa6, 0x2b, 0x2e, 0x70,
|
||||
0x3e, 0xc5, 0x40, 0x60, 0xee, 0x0d, 0xa4, 0x7a, 0x4b, 0x46, 0x7b, 0x9e, 0x8a, 0x25, 0x8f, 0xc3,
|
||||
0xef, 0x79, 0x1e, 0x26, 0xb1, 0xb7, 0xa7, 0xf6, 0xb4, 0x65, 0x94, 0x25, 0x96, 0x44, 0xe8, 0xdd,
|
||||
0x50, 0x59, 0xa2, 0xb5, 0xff, 0x8b, 0x01, 0xce, 0x84, 0x67, 0xab, 0x59, 0xc2, 0xc5, 0xfc, 0x5a,
|
||||
0xb9, 0xbe, 0x07, 0x56, 0x80, 0x51, 0x94, 0x79, 0xe6, 0xd0, 0x1c, 0x0d, 0x0e, 0xee, 0xec, 0xd7,
|
||||
0x45, 0xac, 0xed, 0x1c, 0x61, 0x14, 0x31, 0xb5, 0xcb, 0xfd, 0x08, 0x9c, 0x1c, 0xd7, 0x69, 0xc4,
|
||||
0x73, 0xcc, 0xbc, 0xae, 0xfc, 0xc4, 0x6d, 0x3e, 0x79, 0xae, 0x55, 0xac, 0xd9, 0x74, 0x25, 0x14,
|
||||
0xeb, 0x6a, 0x28, 0xfe, 0x1f, 0x1d, 0xb8, 0xb1, 0x75, 0x9c, 0xbb, 0x07, 0xc6, 0x46, 0x7a, 0x6e,
|
||||
0x31, 0x63, 0x43, 0xa8, 0x94, 0x5e, 0x5b, 0xcc, 0x28, 0x09, 0x5d, 0x48, 0x6e, 0x58, 0xcc, 0xb8,
|
||||
0x20, 0xb4, 0x92, 0x8c, 0xb0, 0x98, 0xb1, 0x72, 0xdf, 0x83, 0xfe, 0x77, 0x05, 0x8a, 0x10, 0x33,
|
||||
0xcf, 0x92, 0xde, 0xfd, 0xaf, 0xf1, 0xee, 0x59, 0x81, 0xa2, 0x64, 0x95, 0x9e, 0xb2, 0x21, 0xd9,
|
||||
0xa4, 0xa8, 0x21, 0xd7, 0x24, 0xcb, 0x89, 0x79, 0x7d, 0x25, 0xa3, 0xb5, 0xce, 0xa2, 0xe2, 0x03,
|
||||
0x65, 0xf1, 0x63, 0xe8, 0xf2, 0x0d, 0x66, 0x9e, 0x23, 0xed, 0xbf, 0xf5, 0x0f, 0x09, 0xdb, 0x1f,
|
||||
0x6f, 0x30, 0xfb, 0x32, 0xce, 0x45, 0xc9, 0xe4, 0x76, 0xf7, 0x5d, 0xe8, 0x05, 0x49, 0x94, 0x88,
|
||||
0xcc, 0x83, 0xcb, 0x8e, 0x1d, 0x91, 0x9c, 0x69, 0xf5, 0xdd, 0x07, 0xe0, 0xd4, 0xdf, 0x12, 0x7d,
|
||||
0x5f, 0x62, 0x29, 0x33, 0xe1, 0x30, 0x5a, 0xba, 0x6f, 0x83, 0x75, 0xce, 0xa3, 0x42, 0x55, 0x71,
|
||||
0x70, 0x70, 0xb3, 0x31, 0x33, 0xde, 0x84, 0x19, 0x53, 0xca, 0x4f, 0x3b, 0x9f, 0x18, 0xfe, 0x12,
|
||||
0x2c, 0x69, 0xb9, 0xc5, 0x03, 0xa7, 0xe2, 0x81, 0xec, 0xaf, 0x4e, 0xab, 0xbf, 0x6e, 0x81, 0xf9,
|
||||
0x15, 0x6e, 0x74, 0xcb, 0xd1, 0xb2, 0x66, 0x4b, 0xb7, 0xc5, 0x96, 0xdb, 0x60, 0x9d, 0xc9, 0xc3,
|
||||
0x55, 0x15, 0x15, 0xf0, 0x7f, 0x36, 0xa0, 0x4b, 0x87, 0x53, 0xad, 0x23, 0x5c, 0xf2, 0xa0, 0x3c,
|
||||
0x4c, 0x8a, 0x78, 0x9e, 0x79, 0xc6, 0xd0, 0x1c, 0x99, 0x6c, 0x4b, 0xe6, 0xbe, 0x06, 0xbd, 0x99,
|
||||
0xd2, 0x76, 0x86, 0xe6, 0xc8, 0x61, 0x1a, 0x91, 0xe9, 0x88, 0xcf, 0x30, 0xd2, 0x2e, 0x28, 0x40,
|
||||
0xbb, 0x53, 0x81, 0x8b, 0x70, 0xa3, 0xdd, 0xd0, 0x88, 0xe4, 0x59, 0xb1, 0x20, 0xb9, 0xf2, 0x44,
|
||||
0x23, 0x72, 0x7a, 0xc6, 0xb3, 0xba, 0xa8, 0xb4, 0x26, 0xcb, 0x59, 0xc0, 0xa3, 0xaa, 0xaa, 0x0a,
|
||||
0xf8, 0xbf, 0x1a, 0xd4, 0xed, 0x8a, 0xa5, 0x57, 0x32, 0xf4, 0x3a, 0xd8, 0xc4, 0xe0, 0x17, 0xe7,
|
||||
0x5c, 0xe8, 0x2c, 0xf5, 0x09, 0x9f, 0x71, 0xe1, 0x7e, 0x08, 0x3d, 0x99, 0xe2, 0x1d, 0x1d, 0x53,
|
||||
0x99, 0x93, 0x59, 0x61, 0x7a, 0x5b, 0xcd, 0xa9, 0x6e, 0x8b, 0x53, 0x75, 0xb0, 0x56, 0x3b, 0xd8,
|
||||
0x7b, 0x60, 0x11, 0x39, 0x4b, 0xe9, 0xfd, 0x4e, 0xcb, 0x8a, 0xc2, 0x6a, 0x97, 0x7f, 0x0a, 0x37,
|
||||
0xb6, 0x4e, 0xac, 0x4f, 0x32, 0xb6, 0x4f, 0x6a, 0xe8, 0xe2, 0x68, 0x7a, 0xd0, 0xa4, 0xcb, 0x30,
|
||||
0xc2, 0x20, 0xc7, 0xb9, 0xcc, 0xb7, 0xcd, 0x6a, 0xec, 0xff, 0x68, 0x34, 0x76, 0xe5, 0x79, 0x34,
|
||||
0xcb, 0x82, 0x64, 0xbd, 0xe6, 0xf1, 0x5c, 0x9b, 0xae, 0x20, 0xe5, 0x6d, 0x3e, 0xd3, 0xa6, 0x3b,
|
||||
0xf3, 0x19, 0x61, 0x91, 0xea, 0x0a, 0x76, 0x44, 0xea, 0x0e, 0x61, 0xb0, 0x46, 0x9e, 0x15, 0x02,
|
||||
0xd7, 0x18, 0xe7, 0x3a, 0x05, 0x6d, 0x91, 0x7b, 0x07, 0xfa, 0x39, 0x5f, 0xbe, 0x20, 0x92, 0xeb,
|
||||
0x4a, 0xe6, 0x7c, 0xf9, 0x10, 0x4b, 0xf7, 0x0d, 0x70, 0x16, 0x21, 0x46, 0x73, 0xa9, 0x52, 0xe5,
|
||||
0xb4, 0xa5, 0xe0, 0x21, 0x96, 0xfe, 0x6f, 0x06, 0xf4, 0xa6, 0x28, 0xce, 0x51, 0x5c, 0x6b, 0xc8,
|
||||
0xb5, 0x2f, 0x0f, 0xf3, 0x15, 0x97, 0x47, 0x77, 0xf7, 0xe5, 0x61, 0x35, 0x97, 0xc7, 0x6d, 0xb0,
|
||||
0xa6, 0x22, 0x38, 0x9e, 0x48, 0x8f, 0x4c, 0xa6, 0x00, 0xb1, 0x71, 0x1c, 0xe4, 0xe1, 0x39, 0xea,
|
||||
0x1b, 0x45, 0xa3, 0x2b, 0xb3, 0xcf, 0xde, 0x31, 0xfb, 0x7e, 0x30, 0xa0, 0xf7, 0x88, 0x97, 0x49,
|
||||
0x91, 0x5f, 0x61, 0xe1, 0x10, 0x06, 0xe3, 0x34, 0x8d, 0xc2, 0x40, 0x7d, 0xad, 0x22, 0x6a, 0x8b,
|
||||
0x68, 0xc7, 0xe3, 0x56, 0x7e, 0x55, 0x6c, 0x6d, 0x11, 0x8d, 0x8b, 0x23, 0x39, 0xdf, 0xd5, 0xb0,
|
||||
0x6e, 0x8d, 0x0b, 0x35, 0xd6, 0xa5, 0x92, 0x92, 0x30, 0x2e, 0xf2, 0x64, 0x11, 0x25, 0x17, 0x32,
|
||||
0x5a, 0x9b, 0xd5, 0xd8, 0xff, 0xbd, 0x03, 0xdd, 0xff, 0x6a, 0x26, 0xef, 0x81, 0x11, 0xea, 0x62,
|
||||
0x1b, 0x61, 0x3d, 0xa1, 0xfb, 0xad, 0x09, 0xed, 0x41, 0xbf, 0x14, 0x3c, 0x5e, 0x62, 0xe6, 0xd9,
|
||||
0x72, 0xba, 0x54, 0x50, 0x6a, 0x64, 0x1f, 0xa9, 0xd1, 0xec, 0xb0, 0x0a, 0xd6, 0x7d, 0x01, 0xad,
|
||||
0xbe, 0xf8, 0x40, 0x4f, 0xf1, 0x81, 0xf4, 0xc8, 0xdb, 0x4e, 0xcb, 0xe5, 0xe1, 0xfd, 0xef, 0xcd,
|
||||
0xe4, 0xbf, 0x0c, 0xb0, 0xea, 0xa6, 0x3a, 0xda, 0x6e, 0xaa, 0xa3, 0xa6, 0xa9, 0x26, 0x87, 0x55,
|
||||
0x53, 0x4d, 0x0e, 0x09, 0xb3, 0x93, 0xaa, 0xa9, 0xd8, 0x09, 0x15, 0xeb, 0x81, 0x48, 0x8a, 0xf4,
|
||||
0xb0, 0x54, 0x55, 0x75, 0x58, 0x8d, 0x89, 0x89, 0xdf, 0xac, 0x50, 0xe8, 0x54, 0x3b, 0x4c, 0x23,
|
||||
0xe2, 0xed, 0x23, 0x39, 0x70, 0x54, 0x72, 0x15, 0x70, 0xdf, 0x01, 0x8b, 0x51, 0xf2, 0x64, 0x86,
|
||||
0xb7, 0xea, 0x22, 0xc5, 0x4c, 0x69, 0xc9, 0xa8, 0x7a, 0xbd, 0x69, 0x02, 0x57, 0x6f, 0xb9, 0xf7,
|
||||
0xa1, 0x37, 0x5d, 0x85, 0x8b, 0xbc, 0xba, 0x0b, 0xff, 0xdf, 0x1a, 0x58, 0xe1, 0x1a, 0xa5, 0x8e,
|
||||
0xe9, 0x2d, 0xfe, 0x33, 0x70, 0x6a, 0x61, 0xe3, 0x8e, 0xd1, 0x76, 0xc7, 0x85, 0xee, 0x69, 0x1c,
|
||||
0xe6, 0x55, 0xeb, 0xd2, 0x9a, 0x82, 0x7d, 0x56, 0xf0, 0x38, 0x0f, 0xf3, 0xb2, 0x6a, 0xdd, 0x0a,
|
||||
0xfb, 0xf7, 0xb5, 0xfb, 0x64, 0xee, 0x34, 0x4d, 0x51, 0xe8, 0x31, 0xa0, 0x80, 0x3c, 0x24, 0xb9,
|
||||
0x40, 0x35, 0xc1, 0x4d, 0xa6, 0x80, 0xff, 0x2d, 0x38, 0xe3, 0x08, 0x45, 0xce, 0x8a, 0x08, 0x77,
|
||||
0xdd, 0x8c, 0x5f, 0x4f, 0x9f, 0x3e, 0xa9, 0x3c, 0xa0, 0x75, 0xd3, 0xf2, 0xe6, 0xa5, 0x96, 0x7f,
|
||||
0xc8, 0x53, 0x7e, 0x3c, 0x91, 0x3c, 0x37, 0x99, 0x46, 0xfe, 0x4f, 0x06, 0x74, 0x69, 0xb6, 0xb4,
|
||||
0x4c, 0x77, 0x5f, 0x35, 0x97, 0x4e, 0x44, 0x72, 0x1e, 0xce, 0x51, 0x54, 0xc1, 0x55, 0x58, 0x26,
|
||||
0x3d, 0x58, 0x61, 0x7d, 0x01, 0x6b, 0x44, 0x5c, 0xa3, 0xa7, 0x5e, 0xd5, 0x4b, 0x2d, 0xae, 0x91,
|
||||
0x98, 0x29, 0xa5, 0xfb, 0x26, 0xc0, 0xb4, 0x48, 0x51, 0x8c, 0xe7, 0xeb, 0x30, 0x96, 0x45, 0xb7,
|
||||
0x59, 0x4b, 0xe2, 0x7f, 0xa1, 0x1e, 0x8f, 0x57, 0x26, 0x94, 0xb1, 0xfb, 0xa1, 0x79, 0xd9, 0x73,
|
||||
0x3f, 0xda, 0xfe, 0xee, 0x5a, 0xd1, 0x0e, 0x61, 0xa0, 0x5f, 0xda, 0xf2, 0xdd, 0xaa, 0x87, 0x55,
|
||||
0x4b, 0x44, 0x31, 0x9f, 0x14, 0xb3, 0x28, 0x0c, 0x64, 0xcc, 0x36, 0xd3, 0xc8, 0x3f, 0x80, 0xde,
|
||||
0x51, 0x12, 0x2f, 0xc2, 0xa5, 0x3b, 0x82, 0xee, 0xb8, 0xc8, 0x57, 0xf2, 0xa4, 0xc1, 0xc1, 0xed,
|
||||
0x56, 0xa3, 0x15, 0xf9, 0x4a, 0xed, 0x61, 0x72, 0x87, 0xff, 0x19, 0x40, 0x23, 0xa3, 0xe7, 0x7b,
|
||||
0x13, 0xfd, 0x13, 0xbc, 0xa0, 0x12, 0x65, 0xd2, 0x8a, 0xcd, 0x76, 0x68, 0xfc, 0xcf, 0xc1, 0x39,
|
||||
0x2c, 0xc2, 0x68, 0x7e, 0x1c, 0x2f, 0x12, 0x6a, 0xd5, 0x33, 0x14, 0x59, 0x93, 0x9f, 0x0a, 0x92,
|
||||
0xc3, 0xd4, 0xb5, 0x35, 0x67, 0x35, 0x9a, 0xf5, 0xe4, 0x1f, 0xd0, 0xfd, 0xbf, 0x03, 0x00, 0x00,
|
||||
0xff, 0xff, 0xa4, 0xe3, 0xbf, 0x66, 0x13, 0x0d, 0x00, 0x00,
|
||||
// 1342 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x8e, 0xe3, 0xc4,
|
||||
0x12, 0x96, 0xe3, 0x38, 0xb1, 0x2b, 0xb3, 0x7b, 0x56, 0x3e, 0xab, 0xb3, 0x3e, 0x7b, 0xa4, 0xa3,
|
||||
0x60, 0x81, 0x08, 0x82, 0x1d, 0xd0, 0xac, 0x90, 0x10, 0x02, 0xa4, 0xcc, 0x04, 0x2d, 0xc3, 0xfe,
|
||||
0xcd, 0x76, 0x76, 0x86, 0x2b, 0xb4, 0xea, 0x38, 0x95, 0xc4, 0x5a, 0xc7, 0x36, 0x6d, 0x7b, 0x26,
|
||||
0xe6, 0x61, 0x90, 0x90, 0x78, 0x02, 0xc4, 0x3d, 0xb7, 0x88, 0x5b, 0xde, 0x81, 0x57, 0xe0, 0x16,
|
||||
0x55, 0x77, 0xfb, 0x27, 0x93, 0xb0, 0xda, 0x0b, 0xc4, 0x5d, 0x7f, 0x55, 0xed, 0xea, 0xfa, 0xf9,
|
||||
0xaa, 0xba, 0x0d, 0x37, 0xc3, 0x38, 0x47, 0x11, 0xf3, 0xe8, 0x30, 0x15, 0x49, 0x9e, 0xb8, 0x76,
|
||||
0x85, 0xfd, 0xdf, 0x3b, 0xd0, 0x9b, 0x26, 0x85, 0x08, 0xd0, 0xbd, 0x09, 0x9d, 0xd3, 0x89, 0x67,
|
||||
0x0c, 0x8d, 0x91, 0xc9, 0x3a, 0xa7, 0x13, 0xd7, 0x85, 0xee, 0x13, 0xbe, 0x46, 0xaf, 0x33, 0x34,
|
||||
0x46, 0x0e, 0x93, 0x6b, 0x92, 0x3d, 0x2f, 0x53, 0xf4, 0x4c, 0x25, 0xa3, 0xb5, 0x7b, 0x17, 0xec,
|
||||
0xf3, 0x8c, 0xac, 0xad, 0xd1, 0xeb, 0x4a, 0x79, 0x8d, 0x49, 0x77, 0xc6, 0xb3, 0xec, 0x2a, 0x11,
|
||||
0x73, 0xcf, 0x52, 0xba, 0x0a, 0xbb, 0xb7, 0xc0, 0x3c, 0x67, 0x8f, 0xbc, 0x9e, 0x14, 0xd3, 0xd2,
|
||||
0xf5, 0xa0, 0x3f, 0xc1, 0x05, 0x2f, 0xa2, 0xdc, 0xeb, 0x0f, 0x8d, 0x91, 0xcd, 0x2a, 0x48, 0x76,
|
||||
0x9e, 0x63, 0x84, 0x4b, 0xc1, 0x17, 0x9e, 0xad, 0xec, 0x54, 0xd8, 0x3d, 0x04, 0xf7, 0x34, 0xce,
|
||||
0x30, 0x28, 0x04, 0x4e, 0x5f, 0x86, 0xe9, 0x05, 0x8a, 0x70, 0x51, 0x7a, 0x8e, 0x34, 0xb0, 0x47,
|
||||
0x43, 0xa7, 0x3c, 0xc6, 0x9c, 0xd3, 0xd9, 0x20, 0x4d, 0x55, 0xd0, 0xf5, 0xe1, 0x60, 0xba, 0xe2,
|
||||
0x02, 0xe7, 0x53, 0x0c, 0x04, 0xe6, 0xde, 0x40, 0xaa, 0xb7, 0x64, 0xb4, 0xe7, 0xa9, 0x58, 0xf2,
|
||||
0x38, 0xfc, 0x96, 0xe7, 0x61, 0x12, 0x7b, 0x07, 0x6a, 0x4f, 0x5b, 0x46, 0x59, 0x62, 0x49, 0x84,
|
||||
0xde, 0x0d, 0x95, 0x25, 0x5a, 0xfb, 0x3f, 0x19, 0xe0, 0x4c, 0x78, 0xb6, 0x9a, 0x25, 0x5c, 0xcc,
|
||||
0x5f, 0x2b, 0xd7, 0xf7, 0xc0, 0x0a, 0x30, 0x8a, 0x32, 0xcf, 0x1c, 0x9a, 0xa3, 0xc1, 0xd1, 0x9d,
|
||||
0xc3, 0xba, 0x88, 0xb5, 0x9d, 0x13, 0x8c, 0x22, 0xa6, 0x76, 0xb9, 0x1f, 0x80, 0x93, 0xe3, 0x3a,
|
||||
0x8d, 0x78, 0x8e, 0x99, 0xd7, 0x95, 0x9f, 0xb8, 0xcd, 0x27, 0xcf, 0xb5, 0x8a, 0x35, 0x9b, 0x76,
|
||||
0x42, 0xb1, 0x76, 0x43, 0xf1, 0x7f, 0xeb, 0xc0, 0x8d, 0xad, 0xe3, 0xdc, 0x03, 0x30, 0x36, 0xd2,
|
||||
0x73, 0x8b, 0x19, 0x1b, 0x42, 0xa5, 0xf4, 0xda, 0x62, 0x46, 0x49, 0xe8, 0x4a, 0x72, 0xc3, 0x62,
|
||||
0xc6, 0x15, 0xa1, 0x95, 0x64, 0x84, 0xc5, 0x8c, 0x95, 0xfb, 0x0e, 0xf4, 0xbf, 0x29, 0x50, 0x84,
|
||||
0x98, 0x79, 0x96, 0xf4, 0xee, 0x5f, 0x8d, 0x77, 0xcf, 0x0a, 0x14, 0x25, 0xab, 0xf4, 0x94, 0x0d,
|
||||
0xc9, 0x26, 0x45, 0x0d, 0xb9, 0x26, 0x59, 0x4e, 0xcc, 0xeb, 0x2b, 0x19, 0xad, 0x75, 0x16, 0x15,
|
||||
0x1f, 0x28, 0x8b, 0x1f, 0x42, 0x97, 0x6f, 0x30, 0xf3, 0x1c, 0x69, 0xff, 0x8d, 0xbf, 0x48, 0xd8,
|
||||
0xe1, 0x78, 0x83, 0xd9, 0xe7, 0x71, 0x2e, 0x4a, 0x26, 0xb7, 0xbb, 0x6f, 0x43, 0x2f, 0x48, 0xa2,
|
||||
0x44, 0x64, 0x1e, 0x5c, 0x77, 0xec, 0x84, 0xe4, 0x4c, 0xab, 0xef, 0x3e, 0x00, 0xa7, 0xfe, 0x96,
|
||||
0xe8, 0xfb, 0x12, 0x4b, 0x99, 0x09, 0x87, 0xd1, 0xd2, 0x7d, 0x13, 0xac, 0x4b, 0x1e, 0x15, 0xaa,
|
||||
0x8a, 0x83, 0xa3, 0x9b, 0x8d, 0x99, 0xf1, 0x26, 0xcc, 0x98, 0x52, 0x7e, 0xdc, 0xf9, 0xc8, 0xf0,
|
||||
0x97, 0x60, 0x49, 0xcb, 0x2d, 0x1e, 0x38, 0x15, 0x0f, 0x64, 0x7f, 0x75, 0x5a, 0xfd, 0x75, 0x0b,
|
||||
0xcc, 0x2f, 0x70, 0xa3, 0x5b, 0x8e, 0x96, 0x35, 0x5b, 0xba, 0x2d, 0xb6, 0xdc, 0x06, 0xeb, 0x42,
|
||||
0x1e, 0xae, 0xaa, 0xa8, 0x80, 0xff, 0xa3, 0x01, 0x5d, 0x3a, 0x9c, 0x6a, 0x1d, 0xe1, 0x92, 0x07,
|
||||
0xe5, 0x71, 0x52, 0xc4, 0xf3, 0xcc, 0x33, 0x86, 0xe6, 0xc8, 0x64, 0x5b, 0x32, 0xf7, 0x3f, 0xd0,
|
||||
0x9b, 0x29, 0x6d, 0x67, 0x68, 0x8e, 0x1c, 0xa6, 0x11, 0x99, 0x8e, 0xf8, 0x0c, 0x23, 0xed, 0x82,
|
||||
0x02, 0xb4, 0x3b, 0x15, 0xb8, 0x08, 0x37, 0xda, 0x0d, 0x8d, 0x48, 0x9e, 0x15, 0x0b, 0x92, 0x2b,
|
||||
0x4f, 0x34, 0x22, 0xa7, 0x67, 0x3c, 0xab, 0x8b, 0x4a, 0x6b, 0xb2, 0x9c, 0x05, 0x3c, 0xaa, 0xaa,
|
||||
0xaa, 0x80, 0xff, 0xb3, 0x41, 0xdd, 0xae, 0x58, 0xba, 0x93, 0xa1, 0xff, 0x82, 0x4d, 0x0c, 0x7e,
|
||||
0x71, 0xc9, 0x85, 0xce, 0x52, 0x9f, 0xf0, 0x05, 0x17, 0xee, 0xfb, 0xd0, 0x93, 0x29, 0xde, 0xd3,
|
||||
0x31, 0x95, 0x39, 0x99, 0x15, 0xa6, 0xb7, 0xd5, 0x9c, 0xea, 0xb6, 0x38, 0x55, 0x07, 0x6b, 0xb5,
|
||||
0x83, 0xbd, 0x07, 0x16, 0x91, 0xb3, 0x94, 0xde, 0xef, 0xb5, 0xac, 0x28, 0xac, 0x76, 0xf9, 0xe7,
|
||||
0x70, 0x63, 0xeb, 0xc4, 0xfa, 0x24, 0x63, 0xfb, 0xa4, 0x86, 0x2e, 0x8e, 0xa6, 0x07, 0x4d, 0xba,
|
||||
0x0c, 0x23, 0x0c, 0x72, 0x9c, 0xcb, 0x7c, 0xdb, 0xac, 0xc6, 0xfe, 0xf7, 0x46, 0x63, 0x57, 0x9e,
|
||||
0x47, 0xb3, 0x2c, 0x48, 0xd6, 0x6b, 0x1e, 0xcf, 0xb5, 0xe9, 0x0a, 0x52, 0xde, 0xe6, 0x33, 0x6d,
|
||||
0xba, 0x33, 0x9f, 0x11, 0x16, 0xa9, 0xae, 0x60, 0x47, 0xa4, 0xee, 0x10, 0x06, 0x6b, 0xe4, 0x59,
|
||||
0x21, 0x70, 0x8d, 0x71, 0xae, 0x53, 0xd0, 0x16, 0xb9, 0x77, 0xa0, 0x9f, 0xf3, 0xe5, 0x0b, 0x22,
|
||||
0xb9, 0xae, 0x64, 0xce, 0x97, 0x0f, 0xb1, 0x74, 0xff, 0x07, 0xce, 0x22, 0xc4, 0x68, 0x2e, 0x55,
|
||||
0xaa, 0x9c, 0xb6, 0x14, 0x3c, 0xc4, 0xd2, 0xff, 0xc5, 0x80, 0xde, 0x14, 0xc5, 0x25, 0x8a, 0xd7,
|
||||
0x1a, 0x72, 0xed, 0xcb, 0xc3, 0x7c, 0xc5, 0xe5, 0xd1, 0xdd, 0x7f, 0x79, 0x58, 0xcd, 0xe5, 0x71,
|
||||
0x1b, 0xac, 0xa9, 0x08, 0x4e, 0x27, 0xd2, 0x23, 0x93, 0x29, 0x40, 0x6c, 0x1c, 0x07, 0x79, 0x78,
|
||||
0x89, 0xfa, 0x46, 0xd1, 0x68, 0x67, 0xf6, 0xd9, 0x7b, 0x66, 0xdf, 0x77, 0x06, 0xf4, 0x1e, 0xf1,
|
||||
0x32, 0x29, 0xf2, 0x1d, 0x16, 0x0e, 0x61, 0x30, 0x4e, 0xd3, 0x28, 0x0c, 0xd4, 0xd7, 0x2a, 0xa2,
|
||||
0xb6, 0x88, 0x76, 0x3c, 0x6e, 0xe5, 0x57, 0xc5, 0xd6, 0x16, 0xd1, 0xb8, 0x38, 0x91, 0xf3, 0x5d,
|
||||
0x0d, 0xeb, 0xd6, 0xb8, 0x50, 0x63, 0x5d, 0x2a, 0x29, 0x09, 0xe3, 0x22, 0x4f, 0x16, 0x51, 0x72,
|
||||
0x25, 0xa3, 0xb5, 0x59, 0x8d, 0xfd, 0x5f, 0x3b, 0xd0, 0xfd, 0xa7, 0x66, 0xf2, 0x01, 0x18, 0xa1,
|
||||
0x2e, 0xb6, 0x11, 0xd6, 0x13, 0xba, 0xdf, 0x9a, 0xd0, 0x1e, 0xf4, 0x4b, 0xc1, 0xe3, 0x25, 0x66,
|
||||
0x9e, 0x2d, 0xa7, 0x4b, 0x05, 0xa5, 0x46, 0xf6, 0x91, 0x1a, 0xcd, 0x0e, 0xab, 0x60, 0xdd, 0x17,
|
||||
0xd0, 0xea, 0x8b, 0xf7, 0xf4, 0x14, 0x1f, 0x48, 0x8f, 0xbc, 0xed, 0xb4, 0x5c, 0x1f, 0xde, 0x7f,
|
||||
0xdf, 0x4c, 0xfe, 0xc3, 0x00, 0xab, 0x6e, 0xaa, 0x93, 0xed, 0xa6, 0x3a, 0x69, 0x9a, 0x6a, 0x72,
|
||||
0x5c, 0x35, 0xd5, 0xe4, 0x98, 0x30, 0x3b, 0xab, 0x9a, 0x8a, 0x9d, 0x51, 0xb1, 0x1e, 0x88, 0xa4,
|
||||
0x48, 0x8f, 0x4b, 0x55, 0x55, 0x87, 0xd5, 0x98, 0x98, 0xf8, 0xd5, 0x0a, 0x85, 0x4e, 0xb5, 0xc3,
|
||||
0x34, 0x22, 0xde, 0x3e, 0x92, 0x03, 0x47, 0x25, 0x57, 0x01, 0xf7, 0x2d, 0xb0, 0x18, 0x25, 0x4f,
|
||||
0x66, 0x78, 0xab, 0x2e, 0x52, 0xcc, 0x94, 0x96, 0x8c, 0xaa, 0xd7, 0x9b, 0x26, 0x70, 0xf5, 0x96,
|
||||
0x7b, 0x17, 0x7a, 0xd3, 0x55, 0xb8, 0xc8, 0xab, 0xbb, 0xf0, 0xdf, 0xad, 0x81, 0x15, 0xae, 0x51,
|
||||
0xea, 0x98, 0xde, 0xe2, 0x3f, 0x03, 0xa7, 0x16, 0x36, 0xee, 0x18, 0x6d, 0x77, 0x5c, 0xe8, 0x9e,
|
||||
0xc7, 0x61, 0x5e, 0xb5, 0x2e, 0xad, 0x29, 0xd8, 0x67, 0x05, 0x8f, 0xf3, 0x30, 0x2f, 0xab, 0xd6,
|
||||
0xad, 0xb0, 0x7f, 0x5f, 0xbb, 0x4f, 0xe6, 0xce, 0xd3, 0x14, 0x85, 0x1e, 0x03, 0x0a, 0xc8, 0x43,
|
||||
0x92, 0x2b, 0x54, 0x13, 0xdc, 0x64, 0x0a, 0xf8, 0x5f, 0x83, 0x33, 0x8e, 0x50, 0xe4, 0xac, 0x88,
|
||||
0x70, 0xdf, 0xcd, 0xf8, 0xe5, 0xf4, 0xe9, 0x93, 0xca, 0x03, 0x5a, 0x37, 0x2d, 0x6f, 0x5e, 0x6b,
|
||||
0xf9, 0x87, 0x3c, 0xe5, 0xa7, 0x13, 0xc9, 0x73, 0x93, 0x69, 0xe4, 0xff, 0x60, 0x40, 0x97, 0x66,
|
||||
0x4b, 0xcb, 0x74, 0xf7, 0x55, 0x73, 0xe9, 0x4c, 0x24, 0x97, 0xe1, 0x1c, 0x45, 0x15, 0x5c, 0x85,
|
||||
0x65, 0xd2, 0x83, 0x15, 0xd6, 0x17, 0xb0, 0x46, 0xc4, 0x35, 0x7a, 0xea, 0x55, 0xbd, 0xd4, 0xe2,
|
||||
0x1a, 0x89, 0x99, 0x52, 0xba, 0xff, 0x07, 0x98, 0x16, 0x29, 0x8a, 0xf1, 0x7c, 0x1d, 0xc6, 0xb2,
|
||||
0xe8, 0x36, 0x6b, 0x49, 0xfc, 0xcf, 0xd4, 0xe3, 0x71, 0x67, 0x42, 0x19, 0xfb, 0x1f, 0x9a, 0xd7,
|
||||
0x3d, 0xf7, 0xa3, 0xed, 0xef, 0xf6, 0x25, 0x72, 0x27, 0xda, 0x21, 0x0c, 0xf4, 0x4b, 0x5b, 0xbe,
|
||||
0x5b, 0xf5, 0xb0, 0x6a, 0x89, 0x28, 0xe6, 0xb3, 0x62, 0x16, 0x85, 0x81, 0x8c, 0xd9, 0x66, 0x1a,
|
||||
0xf9, 0x47, 0xd0, 0x3b, 0x49, 0xe2, 0x45, 0xb8, 0x74, 0x47, 0xd0, 0x1d, 0x17, 0xf9, 0x4a, 0x9e,
|
||||
0x34, 0x38, 0xba, 0xdd, 0x6a, 0xb4, 0x22, 0x5f, 0xa9, 0x3d, 0x4c, 0xee, 0xf0, 0x3f, 0x01, 0x68,
|
||||
0x64, 0xf4, 0x7c, 0x6f, 0xa2, 0x7f, 0x82, 0x57, 0x54, 0xa2, 0x4c, 0x5a, 0xb1, 0xd9, 0x1e, 0x8d,
|
||||
0xff, 0x29, 0x38, 0xc7, 0x45, 0x18, 0xcd, 0x4f, 0xe3, 0x45, 0x42, 0xad, 0x7a, 0x81, 0x22, 0x6b,
|
||||
0xf2, 0x53, 0x41, 0x72, 0x98, 0xba, 0xb6, 0xe6, 0xac, 0x46, 0xb3, 0x9e, 0xfc, 0x03, 0xba, 0xff,
|
||||
0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe, 0x23, 0x76, 0x8f, 0x13, 0x0d, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ message Role {
|
|||
}
|
||||
|
||||
message Organization {
|
||||
uint64 ID = 1; // ID is the unique ID of the organization
|
||||
string ID = 1; // ID is the unique ID of the organization
|
||||
string Name = 2; // Name is the organization's name
|
||||
string DefaultRole = 3; // DefaultRole is the name of the role that is the default for any users added to the organization
|
||||
bool Public = 4; // Public specifies that users must be explicitly added to the organization
|
||||
|
|
|
@ -13,12 +13,14 @@ import (
|
|||
// Ensure OrganizationsStore implements chronograf.OrganizationsStore.
|
||||
var _ chronograf.OrganizationsStore = &OrganizationsStore{}
|
||||
|
||||
// OrganizationsBucket is the bucket where organizations are stored.
|
||||
var OrganizationsBucket = []byte("OrganizationsV1")
|
||||
var (
|
||||
// OrganizationsBucket is the bucket where organizations are stored.
|
||||
OrganizationsBucket = []byte("OrganizationsV1")
|
||||
// DefaultOrganizationID is the ID of the default organization.
|
||||
DefaultOrganizationID = []byte("default")
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultOrganizationID is the ID of the default organization.
|
||||
DefaultOrganizationID uint64 = 0
|
||||
// DefaultOrganizationName is the Name of the default organization
|
||||
DefaultOrganizationName string = "Default"
|
||||
// DefaultOrganizationRole is the DefaultRole for the Default organization
|
||||
|
@ -40,20 +42,20 @@ func (s *OrganizationsStore) Migrate(ctx context.Context) error {
|
|||
// CreateDefault does a findOrCreate on the default organization
|
||||
func (s *OrganizationsStore) CreateDefault(ctx context.Context) error {
|
||||
o := chronograf.Organization{
|
||||
ID: DefaultOrganizationID,
|
||||
ID: string(DefaultOrganizationID),
|
||||
Name: DefaultOrganizationName,
|
||||
DefaultRole: DefaultOrganizationRole,
|
||||
Public: DefaultOrganizationPublic,
|
||||
}
|
||||
return s.client.db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(OrganizationsBucket)
|
||||
v := b.Get(u64tob(o.ID))
|
||||
v := b.Get(DefaultOrganizationID)
|
||||
if v != nil {
|
||||
return nil
|
||||
}
|
||||
if v, err := internal.MarshalOrganization(&o); err != nil {
|
||||
return err
|
||||
} else if err := b.Put(u64tob(o.ID), v); err != nil {
|
||||
} else if err := b.Put(DefaultOrganizationID, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -75,7 +77,7 @@ func (s *OrganizationsStore) nameIsUnique(ctx context.Context, name string) bool
|
|||
func (s *OrganizationsStore) DefaultOrganization(ctx context.Context) (*chronograf.Organization, error) {
|
||||
var org chronograf.Organization
|
||||
if err := s.client.db.View(func(tx *bolt.Tx) error {
|
||||
v := tx.Bucket(OrganizationsBucket).Get(u64tob(DefaultOrganizationID))
|
||||
v := tx.Bucket(OrganizationsBucket).Get(DefaultOrganizationID)
|
||||
return internal.UnmarshalOrganization(v, &org)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
|
@ -89,25 +91,23 @@ func (s *OrganizationsStore) Add(ctx context.Context, o *chronograf.Organization
|
|||
if !s.nameIsUnique(ctx, o.Name) {
|
||||
return nil, chronograf.ErrOrganizationAlreadyExists
|
||||
}
|
||||
if err := s.client.db.Update(func(tx *bolt.Tx) error {
|
||||
err := s.client.db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(OrganizationsBucket)
|
||||
seq, err := b.NextSequence()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.ID = seq
|
||||
if v, err := internal.MarshalOrganization(o); err != nil {
|
||||
return err
|
||||
} else if err := b.Put(u64tob(seq), v); err != nil {
|
||||
o.ID = fmt.Sprintf("%d", seq)
|
||||
|
||||
v, err := internal.MarshalOrganization(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b.Put([]byte(o.ID), v)
|
||||
})
|
||||
|
||||
return o, nil
|
||||
return o, err
|
||||
}
|
||||
|
||||
// All returns all known organizations
|
||||
|
@ -126,7 +126,7 @@ func (s *OrganizationsStore) All(ctx context.Context) ([]chronograf.Organization
|
|||
|
||||
// Delete the organization from OrganizationsStore
|
||||
func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organization) error {
|
||||
if o.ID == DefaultOrganizationID {
|
||||
if o.ID == string(DefaultOrganizationID) {
|
||||
return chronograf.ErrCannotDeleteDefaultOrganization
|
||||
}
|
||||
_, err := s.get(ctx, o.ID)
|
||||
|
@ -134,19 +134,18 @@ func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organizat
|
|||
return err
|
||||
}
|
||||
if err := s.client.db.Update(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket(OrganizationsBucket).Delete(u64tob(o.ID))
|
||||
return tx.Bucket(OrganizationsBucket).Delete([]byte(o.ID))
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Dependent Delete of all resources
|
||||
|
||||
org := fmt.Sprintf("%d", o.ID)
|
||||
// Each of the associated organization stores expects organization to be
|
||||
// set on the context.
|
||||
ctx = context.WithValue(ctx, organizations.ContextKey, org)
|
||||
ctx = context.WithValue(ctx, organizations.ContextKey, o.ID)
|
||||
|
||||
sourcesStore := organizations.NewSourcesStore(s.client.SourcesStore, org)
|
||||
sourcesStore := organizations.NewSourcesStore(s.client.SourcesStore, o.ID)
|
||||
sources, err := sourcesStore.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -157,7 +156,7 @@ func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organizat
|
|||
}
|
||||
}
|
||||
|
||||
serversStore := organizations.NewServersStore(s.client.ServersStore, org)
|
||||
serversStore := organizations.NewServersStore(s.client.ServersStore, o.ID)
|
||||
servers, err := serversStore.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -168,7 +167,7 @@ func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organizat
|
|||
}
|
||||
}
|
||||
|
||||
dashboardsStore := organizations.NewDashboardsStore(s.client.DashboardsStore, org)
|
||||
dashboardsStore := organizations.NewDashboardsStore(s.client.DashboardsStore, o.ID)
|
||||
dashboards, err := dashboardsStore.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -179,7 +178,7 @@ func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organizat
|
|||
}
|
||||
}
|
||||
|
||||
usersStore := organizations.NewUsersStore(s.client.UsersStore, org)
|
||||
usersStore := organizations.NewUsersStore(s.client.UsersStore, o.ID)
|
||||
users, err := usersStore.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -193,10 +192,10 @@ func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organizat
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *OrganizationsStore) get(ctx context.Context, id uint64) (*chronograf.Organization, error) {
|
||||
func (s *OrganizationsStore) get(ctx context.Context, id string) (*chronograf.Organization, error) {
|
||||
var o chronograf.Organization
|
||||
err := s.client.db.View(func(tx *bolt.Tx) error {
|
||||
v := tx.Bucket(OrganizationsBucket).Get(u64tob(id))
|
||||
v := tx.Bucket(OrganizationsBucket).Get([]byte(id))
|
||||
if v == nil {
|
||||
return chronograf.ErrOrganizationNotFound
|
||||
}
|
||||
|
@ -221,7 +220,6 @@ func (s *OrganizationsStore) each(ctx context.Context, fn func(*chronograf.Organ
|
|||
return nil
|
||||
})
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns a Organization if the id exists.
|
||||
|
@ -270,7 +268,7 @@ func (s *OrganizationsStore) Update(ctx context.Context, o *chronograf.Organizat
|
|||
return s.client.db.Update(func(tx *bolt.Tx) error {
|
||||
if v, err := internal.MarshalOrganization(o); err != nil {
|
||||
return err
|
||||
} else if err := tx.Bucket(OrganizationsBucket).Put(u64tob(o.ID), v); err != nil {
|
||||
} else if err := tx.Bucket(OrganizationsBucket).Put([]byte(o.ID), v); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -99,7 +99,7 @@ func TestOrganizationsStore_GetWithID(t *testing.T) {
|
|||
args: args{
|
||||
ctx: context.Background(),
|
||||
org: &chronograf.Organization{
|
||||
ID: 1234,
|
||||
ID: "1234",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
|
@ -180,11 +180,6 @@ func TestOrganizationsStore_All(t *testing.T) {
|
|||
},
|
||||
},
|
||||
want: []chronograf.Organization{
|
||||
{
|
||||
Name: bolt.DefaultOrganizationName,
|
||||
DefaultRole: bolt.DefaultOrganizationRole,
|
||||
Public: bolt.DefaultOrganizationPublic,
|
||||
},
|
||||
{
|
||||
Name: "EE - Evil Empire",
|
||||
DefaultRole: roles.MemberRoleName,
|
||||
|
@ -195,6 +190,11 @@ func TestOrganizationsStore_All(t *testing.T) {
|
|||
DefaultRole: roles.EditorRoleName,
|
||||
Public: true,
|
||||
},
|
||||
{
|
||||
Name: bolt.DefaultOrganizationName,
|
||||
DefaultRole: bolt.DefaultOrganizationRole,
|
||||
Public: bolt.DefaultOrganizationPublic,
|
||||
},
|
||||
},
|
||||
addFirst: true,
|
||||
},
|
||||
|
@ -253,7 +253,7 @@ func TestOrganizationsStore_Update(t *testing.T) {
|
|||
args: args{
|
||||
ctx: context.Background(),
|
||||
initial: &chronograf.Organization{
|
||||
ID: 1234,
|
||||
ID: "1234",
|
||||
Name: "The Okay Place",
|
||||
},
|
||||
updates: &chronograf.Organization{},
|
||||
|
@ -448,7 +448,7 @@ func TestOrganizationStore_Delete(t *testing.T) {
|
|||
args: args{
|
||||
ctx: context.Background(),
|
||||
org: &chronograf.Organization{
|
||||
ID: 10,
|
||||
ID: "10",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
|
@ -615,7 +615,7 @@ func TestOrganizationsStore_DefaultOrganization(t *testing.T) {
|
|||
ctx: context.Background(),
|
||||
},
|
||||
want: &chronograf.Organization{
|
||||
ID: bolt.DefaultOrganizationID,
|
||||
ID: string(bolt.DefaultOrganizationID),
|
||||
Name: bolt.DefaultOrganizationName,
|
||||
DefaultRole: bolt.DefaultOrganizationRole,
|
||||
Public: bolt.DefaultOrganizationPublic,
|
||||
|
|
|
@ -2,7 +2,6 @@ package bolt
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/influxdata/chronograf"
|
||||
|
@ -32,11 +31,9 @@ func (s *ServersStore) Migrate(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
defaultOrgID := fmt.Sprintf("%d", defaultOrg.ID)
|
||||
|
||||
for _, server := range servers {
|
||||
if server.Organization == "" {
|
||||
server.Organization = defaultOrgID
|
||||
server.Organization = defaultOrg.ID
|
||||
if err := s.Update(ctx, server); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package bolt
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/influxdata/chronograf"
|
||||
|
@ -32,11 +31,9 @@ func (s *SourcesStore) Migrate(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
defaultOrgID := fmt.Sprintf("%d", defaultOrg.ID)
|
||||
|
||||
for _, source := range sources {
|
||||
if source.Organization == "" {
|
||||
source.Organization = defaultOrgID
|
||||
source.Organization = defaultOrg.ID
|
||||
}
|
||||
if source.Role == "" {
|
||||
source.Role = roles.ViewerRoleName
|
||||
|
|
|
@ -2,7 +2,6 @@ package bolt_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
@ -301,9 +300,7 @@ func TestUsersStore_Delete(t *testing.T) {
|
|||
s := client.UsersStore
|
||||
|
||||
if tt.addFirst {
|
||||
var err error
|
||||
tt.args.user, err = s.Add(tt.args.ctx, tt.args.user)
|
||||
fmt.Println(err)
|
||||
tt.args.user, _ = s.Add(tt.args.ctx, tt.args.user)
|
||||
}
|
||||
if err := s.Delete(tt.args.ctx, tt.args.user); (err != nil) != tt.wantErr {
|
||||
t.Errorf("%q. UsersStore.Delete() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
|
|
|
@ -16,6 +16,9 @@ const (
|
|||
ErrDashboardNotFound = Error("dashboard not found")
|
||||
ErrUserNotFound = Error("user not found")
|
||||
ErrLayoutInvalid = Error("layout is invalid")
|
||||
ErrDashboardInvalid = Error("dashboard is invalid")
|
||||
ErrSourceInvalid = Error("source is invalid")
|
||||
ErrServerInvalid = Error("server is invalid")
|
||||
ErrAlertNotFound = Error("alert not found")
|
||||
ErrAuthentication = Error("user not authenticated")
|
||||
ErrUninitialized = Error("client uninitialized. Call Open() method")
|
||||
|
@ -562,7 +565,7 @@ type LayoutsStore interface {
|
|||
|
||||
// Organization is a group of resources under a common name
|
||||
type Organization struct {
|
||||
ID uint64 `json:"id,string"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
// DefaultRole is the name of the role that is the default for any users added to the organization
|
||||
DefaultRole string `json:"defaultRole,omitempty"`
|
||||
|
@ -576,7 +579,7 @@ type Organization struct {
|
|||
// It is expected that only one of ID or Name will be specified, but will prefer ID over Name if both are specified.
|
||||
type OrganizationQuery struct {
|
||||
// If an ID is provided in the query, the lookup time for an organization will be O(1).
|
||||
ID *uint64
|
||||
ID *string
|
||||
// If Name is provided, the lookup time will be O(n).
|
||||
Name *string
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package canned
|
||||
package filestore
|
||||
|
||||
import (
|
||||
"context"
|
|
@ -1,4 +1,4 @@
|
|||
package canned_test
|
||||
package filestore_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -13,7 +13,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/canned"
|
||||
"github.com/influxdata/chronograf/filestore"
|
||||
clog "github.com/influxdata/chronograf/log"
|
||||
)
|
||||
|
||||
|
@ -47,7 +47,7 @@ func TestAll(t *testing.T) {
|
|||
apps, _ := MockApps(test.Existing, test.Err)
|
||||
layouts, err := apps.All(context.Background())
|
||||
if err != test.Err {
|
||||
t.Errorf("Test %d: Canned all error expected: %v; actual: %v", i, test.Err, err)
|
||||
t.Errorf("Test %d: apps all error expected: %v; actual: %v", i, test.Err, err)
|
||||
}
|
||||
if !reflect.DeepEqual(layouts, test.Existing) {
|
||||
t.Errorf("Test %d: Layouts should be equal; expected %v; actual %v", i, test.Existing, layouts)
|
||||
|
@ -99,7 +99,7 @@ func TestAdd(t *testing.T) {
|
|||
apps, _ := MockApps(test.Existing, test.Err)
|
||||
layout, err := apps.Add(context.Background(), test.Add)
|
||||
if err != test.Err {
|
||||
t.Errorf("Test %d: Canned add error expected: %v; actual: %v", i, test.Err, err)
|
||||
t.Errorf("Test %d: apps add error expected: %v; actual: %v", i, test.Err, err)
|
||||
}
|
||||
|
||||
if layout.ID != test.ExpectedID {
|
||||
|
@ -150,7 +150,7 @@ func TestDelete(t *testing.T) {
|
|||
apps, actual := MockApps(test.Existing, test.Err)
|
||||
err := apps.Delete(context.Background(), chronograf.Layout{ID: test.DeleteID})
|
||||
if err != test.Err {
|
||||
t.Errorf("Test %d: Canned delete error expected: %v; actual: %v", i, test.Err, err)
|
||||
t.Errorf("Test %d: apps delete error expected: %v; actual: %v", i, test.Err, err)
|
||||
}
|
||||
if !reflect.DeepEqual(*actual, test.Expected) {
|
||||
t.Errorf("Test %d: Layouts should be equal; expected %v; actual %v", i, test.Expected, actual)
|
||||
|
@ -199,7 +199,7 @@ func TestGet(t *testing.T) {
|
|||
apps, _ := MockApps(test.Existing, test.Err)
|
||||
layout, err := apps.Get(context.Background(), test.ID)
|
||||
if err != test.Err {
|
||||
t.Errorf("Test %d: Canned get error expected: %v; actual: %v", i, test.Err, err)
|
||||
t.Errorf("Test %d: Layouts get error expected: %v; actual: %v", i, test.Err, err)
|
||||
}
|
||||
if !reflect.DeepEqual(layout, test.Expected) {
|
||||
t.Errorf("Test %d: Layouts should be equal; expected %v; actual %v", i, test.Expected, layout)
|
||||
|
@ -261,7 +261,7 @@ func TestUpdate(t *testing.T) {
|
|||
apps, actual := MockApps(test.Existing, test.Err)
|
||||
err := apps.Update(context.Background(), test.Update)
|
||||
if err != test.Err {
|
||||
t.Errorf("Test %d: Canned get error expected: %v; actual: %v", i, test.Err, err)
|
||||
t.Errorf("Test %d: Layouts get error expected: %v; actual: %v", i, test.Err, err)
|
||||
}
|
||||
if !reflect.DeepEqual(*actual, test.Expected) {
|
||||
t.Errorf("Test %d: Layouts should be equal; expected %v; actual %v", i, test.Expected, actual)
|
||||
|
@ -312,7 +312,7 @@ func (m *MockID) Generate() (string, error) {
|
|||
return strconv.Itoa(m.id), nil
|
||||
}
|
||||
|
||||
func MockApps(existing []chronograf.Layout, expected error) (canned.Apps, *map[string]chronograf.Layout) {
|
||||
func MockApps(existing []chronograf.Layout, expected error) (filestore.Apps, *map[string]chronograf.Layout) {
|
||||
layouts := map[string]chronograf.Layout{}
|
||||
fileName := func(dir string, layout chronograf.Layout) string {
|
||||
return path.Join(dir, layout.ID+".json")
|
||||
|
@ -326,11 +326,11 @@ func MockApps(existing []chronograf.Layout, expected error) (canned.Apps, *map[s
|
|||
return chronograf.Layout{}, expected
|
||||
}
|
||||
|
||||
if l, ok := layouts[file]; !ok {
|
||||
l, ok := layouts[file]
|
||||
if !ok {
|
||||
return chronograf.Layout{}, chronograf.ErrLayoutNotFound
|
||||
} else {
|
||||
return l, nil
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
create := func(file string, layout chronograf.Layout) error {
|
||||
|
@ -346,7 +346,7 @@ func MockApps(existing []chronograf.Layout, expected error) (canned.Apps, *map[s
|
|||
return nil, expected
|
||||
}
|
||||
info := []os.FileInfo{}
|
||||
for k, _ := range layouts {
|
||||
for k := range layouts {
|
||||
info = append(info, &MockFileInfo{filepath.Base(k)})
|
||||
}
|
||||
sort.Sort(MockFileInfos(info))
|
||||
|
@ -364,7 +364,7 @@ func MockApps(existing []chronograf.Layout, expected error) (canned.Apps, *map[s
|
|||
return nil
|
||||
}
|
||||
|
||||
return canned.Apps{
|
||||
return filestore.Apps{
|
||||
Dir: dir,
|
||||
Load: load,
|
||||
Filename: fileName,
|
|
@ -0,0 +1,210 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// DashExt is the the file extension searched for in the directory for dashboard files
|
||||
const DashExt = ".dashboard"
|
||||
|
||||
var _ chronograf.DashboardsStore = &Dashboards{}
|
||||
|
||||
// Dashboards are JSON dashboards stored in the filesystem
|
||||
type Dashboards struct {
|
||||
Dir string // Dir is the directory containing the dashboards.
|
||||
Load func(string, interface{}) error // Load loads string name and dashbaord passed in as interface
|
||||
Create func(string, interface{}) error // Create will write dashboard to file.
|
||||
ReadDir func(dirname string) ([]os.FileInfo, error) // ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
|
||||
Remove func(name string) error // Remove file
|
||||
IDs chronograf.ID // IDs generate unique ids for new dashboards
|
||||
Logger chronograf.Logger
|
||||
}
|
||||
|
||||
// NewDashboards constructs a dashboard store wrapping a file system directory
|
||||
func NewDashboards(dir string, ids chronograf.ID, logger chronograf.Logger) chronograf.DashboardsStore {
|
||||
return &Dashboards{
|
||||
Dir: dir,
|
||||
Load: load,
|
||||
Create: create,
|
||||
ReadDir: ioutil.ReadDir,
|
||||
Remove: os.Remove,
|
||||
IDs: ids,
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func dashboardFile(dir string, dashboard chronograf.Dashboard) string {
|
||||
base := fmt.Sprintf("%s%s", dashboard.Name, DashExt)
|
||||
return path.Join(dir, base)
|
||||
}
|
||||
|
||||
func load(name string, resource interface{}) error {
|
||||
octets, err := templatedFromEnv(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resource %s not found", name)
|
||||
}
|
||||
|
||||
return json.Unmarshal(octets, resource)
|
||||
}
|
||||
|
||||
func create(file string, resource interface{}) error {
|
||||
h, err := os.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer h.Close()
|
||||
|
||||
octets, err := json.MarshalIndent(resource, " ", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = h.Write(octets)
|
||||
return err
|
||||
}
|
||||
|
||||
// All returns all dashboards from the directory
|
||||
func (d *Dashboards) All(ctx context.Context) ([]chronograf.Dashboard, error) {
|
||||
files, err := d.ReadDir(d.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dashboards := []chronograf.Dashboard{}
|
||||
for _, file := range files {
|
||||
if path.Ext(file.Name()) != DashExt {
|
||||
continue
|
||||
}
|
||||
var dashboard chronograf.Dashboard
|
||||
if err := d.Load(path.Join(d.Dir, file.Name()), &dashboard); err != nil {
|
||||
continue // We want to load all files we can.
|
||||
} else {
|
||||
dashboards = append(dashboards, dashboard)
|
||||
}
|
||||
}
|
||||
return dashboards, nil
|
||||
}
|
||||
|
||||
// Add creates a new dashboard within the directory
|
||||
func (d *Dashboards) Add(ctx context.Context, dashboard chronograf.Dashboard) (chronograf.Dashboard, error) {
|
||||
genID, err := d.IDs.Generate()
|
||||
if err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
Error("Unable to generate ID")
|
||||
return chronograf.Dashboard{}, err
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(genID)
|
||||
if err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
Error("Unable to convert ID")
|
||||
return chronograf.Dashboard{}, err
|
||||
}
|
||||
|
||||
dashboard.ID = chronograf.DashboardID(id)
|
||||
|
||||
file := dashboardFile(d.Dir, dashboard)
|
||||
if err = d.Create(file, dashboard); err != nil {
|
||||
if err == chronograf.ErrDashboardInvalid {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
WithField("name", file).
|
||||
Error("Invalid Dashboard: ", err)
|
||||
} else {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
WithField("name", file).
|
||||
Error("Unable to write dashboard:", err)
|
||||
}
|
||||
return chronograf.Dashboard{}, err
|
||||
}
|
||||
return dashboard, nil
|
||||
}
|
||||
|
||||
// Delete removes a dashboard file from the directory
|
||||
func (d *Dashboards) Delete(ctx context.Context, dashboard chronograf.Dashboard) error {
|
||||
_, file, err := d.idToFile(dashboard.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.Remove(file); err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
WithField("name", file).
|
||||
Error("Unable to remove dashboard:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns a dashboard file from the dashboard directory
|
||||
func (d *Dashboards) Get(ctx context.Context, id chronograf.DashboardID) (chronograf.Dashboard, error) {
|
||||
board, file, err := d.idToFile(id)
|
||||
if err != nil {
|
||||
if err == chronograf.ErrDashboardNotFound {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
WithField("name", file).
|
||||
Error("Unable to read file")
|
||||
} else if err == chronograf.ErrDashboardInvalid {
|
||||
d.Logger.
|
||||
WithField("component", "dashboard").
|
||||
WithField("name", file).
|
||||
Error("File is not a dashboard")
|
||||
}
|
||||
return chronograf.Dashboard{}, err
|
||||
}
|
||||
return board, nil
|
||||
}
|
||||
|
||||
// Update replaces a dashboard from the file system directory
|
||||
func (d *Dashboards) Update(ctx context.Context, dashboard chronograf.Dashboard) error {
|
||||
board, _, err := d.idToFile(dashboard.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.Delete(ctx, board); err != nil {
|
||||
return err
|
||||
}
|
||||
file := dashboardFile(d.Dir, dashboard)
|
||||
return d.Create(file, dashboard)
|
||||
}
|
||||
|
||||
// idToFile takes an id and finds the associated filename
|
||||
func (d *Dashboards) idToFile(id chronograf.DashboardID) (chronograf.Dashboard, string, error) {
|
||||
// Because the entire dashboard information is not known at this point, we need
|
||||
// to try to find the name of the file through matching the ID in the dashboard
|
||||
// content with the ID passed.
|
||||
files, err := d.ReadDir(d.Dir)
|
||||
if err != nil {
|
||||
return chronograf.Dashboard{}, "", err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if path.Ext(f.Name()) != DashExt {
|
||||
continue
|
||||
}
|
||||
file := path.Join(d.Dir, f.Name())
|
||||
var dashboard chronograf.Dashboard
|
||||
if err := d.Load(file, &dashboard); err != nil {
|
||||
return chronograf.Dashboard{}, "", err
|
||||
}
|
||||
if dashboard.ID == id {
|
||||
return dashboard, file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return chronograf.Dashboard{}, "", chronograf.ErrDashboardNotFound
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var env map[string]string
|
||||
|
||||
// environ returns a map of all environment variables in the running process
|
||||
func environ() map[string]string {
|
||||
if env == nil {
|
||||
env = make(map[string]string)
|
||||
envVars := os.Environ()
|
||||
for _, envVar := range envVars {
|
||||
kv := strings.SplitN(envVar, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
continue
|
||||
}
|
||||
env[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
return env
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_environ(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
key string
|
||||
value string
|
||||
}{
|
||||
{
|
||||
name: "environment variable is returned",
|
||||
key: "CHRONOGRAF_TEST_ENVIRON",
|
||||
value: "howdy",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
os.Setenv(tt.key, tt.value)
|
||||
got := environ()
|
||||
if v, ok := got[tt.key]; !ok || v != tt.value {
|
||||
t.Errorf("environ() = %v, want %v", v, tt.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// KapExt is the the file extension searched for in the directory for kapacitor files
|
||||
const KapExt = ".kap"
|
||||
|
||||
var _ chronograf.ServersStore = &Kapacitors{}
|
||||
|
||||
// Kapacitors are JSON kapacitors stored in the filesystem
|
||||
type Kapacitors struct {
|
||||
Dir string // Dir is the directory containing the kapacitors.
|
||||
Load func(string, interface{}) error // Load loads string name and dashbaord passed in as interface
|
||||
Create func(string, interface{}) error // Create will write kapacitor to file.
|
||||
ReadDir func(dirname string) ([]os.FileInfo, error) // ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
|
||||
Remove func(name string) error // Remove file
|
||||
IDs chronograf.ID // IDs generate unique ids for new kapacitors
|
||||
Logger chronograf.Logger
|
||||
}
|
||||
|
||||
// NewKapacitors constructs a kapacitor store wrapping a file system directory
|
||||
func NewKapacitors(dir string, ids chronograf.ID, logger chronograf.Logger) chronograf.ServersStore {
|
||||
return &Kapacitors{
|
||||
Dir: dir,
|
||||
Load: load,
|
||||
Create: create,
|
||||
ReadDir: ioutil.ReadDir,
|
||||
Remove: os.Remove,
|
||||
IDs: ids,
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func kapacitorFile(dir string, kapacitor chronograf.Server) string {
|
||||
base := fmt.Sprintf("%s%s", kapacitor.Name, KapExt)
|
||||
return path.Join(dir, base)
|
||||
}
|
||||
|
||||
// All returns all kapacitors from the directory
|
||||
func (d *Kapacitors) All(ctx context.Context) ([]chronograf.Server, error) {
|
||||
files, err := d.ReadDir(d.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kapacitors := []chronograf.Server{}
|
||||
for _, file := range files {
|
||||
if path.Ext(file.Name()) != KapExt {
|
||||
continue
|
||||
}
|
||||
var kapacitor chronograf.Server
|
||||
if err := d.Load(path.Join(d.Dir, file.Name()), &kapacitor); err != nil {
|
||||
continue // We want to load all files we can.
|
||||
} else {
|
||||
kapacitors = append(kapacitors, kapacitor)
|
||||
}
|
||||
}
|
||||
return kapacitors, nil
|
||||
}
|
||||
|
||||
// Add creates a new kapacitor within the directory
|
||||
func (d *Kapacitors) Add(ctx context.Context, kapacitor chronograf.Server) (chronograf.Server, error) {
|
||||
genID, err := d.IDs.Generate()
|
||||
if err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
Error("Unable to generate ID")
|
||||
return chronograf.Server{}, err
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(genID)
|
||||
if err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
Error("Unable to convert ID")
|
||||
return chronograf.Server{}, err
|
||||
}
|
||||
|
||||
kapacitor.ID = id
|
||||
|
||||
file := kapacitorFile(d.Dir, kapacitor)
|
||||
if err = d.Create(file, kapacitor); err != nil {
|
||||
if err == chronograf.ErrServerInvalid {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
WithField("name", file).
|
||||
Error("Invalid Server: ", err)
|
||||
} else {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
WithField("name", file).
|
||||
Error("Unable to write kapacitor:", err)
|
||||
}
|
||||
return chronograf.Server{}, err
|
||||
}
|
||||
return kapacitor, nil
|
||||
}
|
||||
|
||||
// Delete removes a kapacitor file from the directory
|
||||
func (d *Kapacitors) Delete(ctx context.Context, kapacitor chronograf.Server) error {
|
||||
_, file, err := d.idToFile(kapacitor.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.Remove(file); err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
WithField("name", file).
|
||||
Error("Unable to remove kapacitor:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns a kapacitor file from the kapacitor directory
|
||||
func (d *Kapacitors) Get(ctx context.Context, id int) (chronograf.Server, error) {
|
||||
board, file, err := d.idToFile(id)
|
||||
if err != nil {
|
||||
if err == chronograf.ErrServerNotFound {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
WithField("name", file).
|
||||
Error("Unable to read file")
|
||||
} else if err == chronograf.ErrServerInvalid {
|
||||
d.Logger.
|
||||
WithField("component", "kapacitor").
|
||||
WithField("name", file).
|
||||
Error("File is not a kapacitor")
|
||||
}
|
||||
return chronograf.Server{}, err
|
||||
}
|
||||
return board, nil
|
||||
}
|
||||
|
||||
// Update replaces a kapacitor from the file system directory
|
||||
func (d *Kapacitors) Update(ctx context.Context, kapacitor chronograf.Server) error {
|
||||
board, _, err := d.idToFile(kapacitor.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.Delete(ctx, board); err != nil {
|
||||
return err
|
||||
}
|
||||
file := kapacitorFile(d.Dir, kapacitor)
|
||||
return d.Create(file, kapacitor)
|
||||
}
|
||||
|
||||
// idToFile takes an id and finds the associated filename
|
||||
func (d *Kapacitors) idToFile(id int) (chronograf.Server, string, error) {
|
||||
// Because the entire kapacitor information is not known at this point, we need
|
||||
// to try to find the name of the file through matching the ID in the kapacitor
|
||||
// content with the ID passed.
|
||||
files, err := d.ReadDir(d.Dir)
|
||||
if err != nil {
|
||||
return chronograf.Server{}, "", err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if path.Ext(f.Name()) != KapExt {
|
||||
continue
|
||||
}
|
||||
file := path.Join(d.Dir, f.Name())
|
||||
var kapacitor chronograf.Server
|
||||
if err := d.Load(file, &kapacitor); err != nil {
|
||||
return chronograf.Server{}, "", err
|
||||
}
|
||||
if kapacitor.ID == id {
|
||||
return kapacitor, file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return chronograf.Server{}, "", chronograf.ErrServerNotFound
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// OrgExt is the the file extension searched for in the directory for org files
|
||||
const OrgExt = ".org"
|
||||
|
||||
var _ chronograf.OrganizationsStore = &Organizations{}
|
||||
|
||||
// Organizations are JSON orgs stored in the filesystem
|
||||
type Organizations struct {
|
||||
Dir string // Dir is the directory containing the orgs.
|
||||
Load func(string, interface{}) error // Load loads string name and org passed in as interface
|
||||
ReadDir func(dirname string) ([]os.FileInfo, error) // ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
|
||||
Logger chronograf.Logger
|
||||
}
|
||||
|
||||
// NewOrganizations constructs a org store wrapping a file system directory
|
||||
func NewOrganizations(dir string, logger chronograf.Logger) chronograf.OrganizationsStore {
|
||||
return &Organizations{
|
||||
Dir: dir,
|
||||
Load: load,
|
||||
ReadDir: ioutil.ReadDir,
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func orgFile(dir string, org chronograf.Organization) string {
|
||||
base := fmt.Sprintf("%s%s", org.Name, OrgExt)
|
||||
return path.Join(dir, base)
|
||||
}
|
||||
|
||||
// All returns all orgs from the directory
|
||||
func (o *Organizations) All(ctx context.Context) ([]chronograf.Organization, error) {
|
||||
files, err := o.ReadDir(o.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orgs := []chronograf.Organization{}
|
||||
for _, file := range files {
|
||||
if path.Ext(file.Name()) != OrgExt {
|
||||
continue
|
||||
}
|
||||
var org chronograf.Organization
|
||||
if err := o.Load(path.Join(o.Dir, file.Name()), &org); err != nil {
|
||||
continue // We want to load all files we can.
|
||||
} else {
|
||||
orgs = append(orgs, org)
|
||||
}
|
||||
}
|
||||
return orgs, nil
|
||||
}
|
||||
|
||||
// Get returns a org file from the org directory
|
||||
func (o *Organizations) Get(ctx context.Context, query chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
org, _, err := o.findOrg(query)
|
||||
return org, err
|
||||
}
|
||||
|
||||
// Add is not allowed for the filesystem organization store
|
||||
func (o *Organizations) Add(ctx context.Context, org *chronograf.Organization) (*chronograf.Organization, error) {
|
||||
return nil, fmt.Errorf("unable to add organizations to the filesystem")
|
||||
}
|
||||
|
||||
// Delete is not allowed for the filesystem organization store
|
||||
func (o *Organizations) Delete(ctx context.Context, org *chronograf.Organization) error {
|
||||
return fmt.Errorf("unable to delete an organization from the filesystem")
|
||||
}
|
||||
|
||||
// Update is not allowed for the filesystem organization store
|
||||
func (o *Organizations) Update(ctx context.Context, org *chronograf.Organization) error {
|
||||
return fmt.Errorf("unable to update organizations on the filesystem")
|
||||
}
|
||||
|
||||
// CreateDefault is not allowed for the filesystem organization store
|
||||
func (o *Organizations) CreateDefault(ctx context.Context) error {
|
||||
return fmt.Errorf("unable to create default organizations on the filesystem")
|
||||
}
|
||||
|
||||
// DefaultOrganization is not allowed for the filesystem organization store
|
||||
func (o *Organizations) DefaultOrganization(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return nil, fmt.Errorf("unable to get default organizations from the filestore")
|
||||
}
|
||||
|
||||
// findOrg takes an OrganizationQuery and finds the associated filename
|
||||
func (o *Organizations) findOrg(query chronograf.OrganizationQuery) (*chronograf.Organization, string, error) {
|
||||
// Because the entire org information is not known at this point, we need
|
||||
// to try to find the name of the file through matching the ID or name in the org
|
||||
// content with the ID passed.
|
||||
files, err := o.ReadDir(o.Dir)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if path.Ext(f.Name()) != OrgExt {
|
||||
continue
|
||||
}
|
||||
file := path.Join(o.Dir, f.Name())
|
||||
var org chronograf.Organization
|
||||
if err := o.Load(file, &org); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if query.ID != nil && org.ID == *query.ID {
|
||||
return &org, file, nil
|
||||
}
|
||||
if query.Name != nil && org.Name == *query.Name {
|
||||
return &org, file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "", chronograf.ErrOrganizationNotFound
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// SrcExt is the the file extension searched for in the directory for source files
|
||||
const SrcExt = ".src"
|
||||
|
||||
var _ chronograf.SourcesStore = &Sources{}
|
||||
|
||||
// Sources are JSON sources stored in the filesystem
|
||||
type Sources struct {
|
||||
Dir string // Dir is the directory containing the sources.
|
||||
Load func(string, interface{}) error // Load loads string name and dashbaord passed in as interface
|
||||
Create func(string, interface{}) error // Create will write source to file.
|
||||
ReadDir func(dirname string) ([]os.FileInfo, error) // ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
|
||||
Remove func(name string) error // Remove file
|
||||
IDs chronograf.ID // IDs generate unique ids for new sources
|
||||
Logger chronograf.Logger
|
||||
}
|
||||
|
||||
// NewSources constructs a source store wrapping a file system directory
|
||||
func NewSources(dir string, ids chronograf.ID, logger chronograf.Logger) chronograf.SourcesStore {
|
||||
return &Sources{
|
||||
Dir: dir,
|
||||
Load: load,
|
||||
Create: create,
|
||||
ReadDir: ioutil.ReadDir,
|
||||
Remove: os.Remove,
|
||||
IDs: ids,
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func sourceFile(dir string, source chronograf.Source) string {
|
||||
base := fmt.Sprintf("%s%s", source.Name, SrcExt)
|
||||
return path.Join(dir, base)
|
||||
}
|
||||
|
||||
// All returns all sources from the directory
|
||||
func (d *Sources) All(ctx context.Context) ([]chronograf.Source, error) {
|
||||
files, err := d.ReadDir(d.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sources := []chronograf.Source{}
|
||||
for _, file := range files {
|
||||
if path.Ext(file.Name()) != SrcExt {
|
||||
continue
|
||||
}
|
||||
var source chronograf.Source
|
||||
if err := d.Load(path.Join(d.Dir, file.Name()), &source); err != nil {
|
||||
continue // We want to load all files we can.
|
||||
} else {
|
||||
sources = append(sources, source)
|
||||
}
|
||||
}
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
// Add creates a new source within the directory
|
||||
func (d *Sources) Add(ctx context.Context, source chronograf.Source) (chronograf.Source, error) {
|
||||
genID, err := d.IDs.Generate()
|
||||
if err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
Error("Unable to generate ID")
|
||||
return chronograf.Source{}, err
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(genID)
|
||||
if err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
Error("Unable to convert ID")
|
||||
return chronograf.Source{}, err
|
||||
}
|
||||
|
||||
source.ID = id
|
||||
|
||||
file := sourceFile(d.Dir, source)
|
||||
if err = d.Create(file, source); err != nil {
|
||||
if err == chronograf.ErrSourceInvalid {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
WithField("name", file).
|
||||
Error("Invalid Source: ", err)
|
||||
} else {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
WithField("name", file).
|
||||
Error("Unable to write source:", err)
|
||||
}
|
||||
return chronograf.Source{}, err
|
||||
}
|
||||
return source, nil
|
||||
}
|
||||
|
||||
// Delete removes a source file from the directory
|
||||
func (d *Sources) Delete(ctx context.Context, source chronograf.Source) error {
|
||||
_, file, err := d.idToFile(source.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.Remove(file); err != nil {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
WithField("name", file).
|
||||
Error("Unable to remove source:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns a source file from the source directory
|
||||
func (d *Sources) Get(ctx context.Context, id int) (chronograf.Source, error) {
|
||||
board, file, err := d.idToFile(id)
|
||||
if err != nil {
|
||||
if err == chronograf.ErrSourceNotFound {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
WithField("name", file).
|
||||
Error("Unable to read file")
|
||||
} else if err == chronograf.ErrSourceInvalid {
|
||||
d.Logger.
|
||||
WithField("component", "source").
|
||||
WithField("name", file).
|
||||
Error("File is not a source")
|
||||
}
|
||||
return chronograf.Source{}, err
|
||||
}
|
||||
return board, nil
|
||||
}
|
||||
|
||||
// Update replaces a source from the file system directory
|
||||
func (d *Sources) Update(ctx context.Context, source chronograf.Source) error {
|
||||
board, _, err := d.idToFile(source.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.Delete(ctx, board); err != nil {
|
||||
return err
|
||||
}
|
||||
file := sourceFile(d.Dir, source)
|
||||
return d.Create(file, source)
|
||||
}
|
||||
|
||||
// idToFile takes an id and finds the associated filename
|
||||
func (d *Sources) idToFile(id int) (chronograf.Source, string, error) {
|
||||
// Because the entire source information is not known at this point, we need
|
||||
// to try to find the name of the file through matching the ID in the source
|
||||
// content with the ID passed.
|
||||
files, err := d.ReadDir(d.Dir)
|
||||
if err != nil {
|
||||
return chronograf.Source{}, "", err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if path.Ext(f.Name()) != SrcExt {
|
||||
continue
|
||||
}
|
||||
file := path.Join(d.Dir, f.Name())
|
||||
var source chronograf.Source
|
||||
if err := d.Load(file, &source); err != nil {
|
||||
return chronograf.Source{}, "", err
|
||||
}
|
||||
if source.ID == id {
|
||||
return source, file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return chronograf.Source{}, "", chronograf.ErrSourceNotFound
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
// templated returns all files templated using data
|
||||
func templated(data interface{}, filenames ...string) ([]byte, error) {
|
||||
t, err := template.ParseFiles(filenames...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var b bytes.Buffer
|
||||
// If a key in the file exists but is not in the data we
|
||||
// immediately fail with a missing key error
|
||||
err = t.Option("missingkey=error").Execute(&b, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
// templatedFromEnv returns all files templated against environment variables
|
||||
func templatedFromEnv(filenames ...string) ([]byte, error) {
|
||||
return templated(environ(), filenames...)
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package filestore
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_templated(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
content []string
|
||||
data interface{}
|
||||
want []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "files with templates are rendered correctly",
|
||||
content: []string{
|
||||
"{{ .MYVAR }}",
|
||||
},
|
||||
data: map[string]string{
|
||||
"MYVAR": "howdy",
|
||||
},
|
||||
want: []byte("howdy"),
|
||||
},
|
||||
{
|
||||
name: "missing key gives an error",
|
||||
content: []string{
|
||||
"{{ .MYVAR }}",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no files make me an error!",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
filenames := make([]string, len(tt.content))
|
||||
for i, c := range tt.content {
|
||||
f, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write([]byte(c)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filenames[i] = f.Name()
|
||||
defer os.Remove(f.Name())
|
||||
}
|
||||
got, err := templated(tt.data, filenames...)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("templated() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("templated() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package id
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// tm generates an id based on current time
|
||||
type tm struct {
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
// NewTime builds a chronograf.ID generator based on current time
|
||||
func NewTime() chronograf.ID {
|
||||
return &tm{
|
||||
Now: time.Now,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate creates a string based on the current time as an integer
|
||||
func (i *tm) Generate() (string, error) {
|
||||
return strconv.Itoa(int(i.Now().Unix())), nil
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package id
|
||||
|
||||
import (
|
||||
"github.com/influxdata/chronograf"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
var _ chronograf.ID = &UUID{}
|
||||
|
||||
// UUID generates a V4 uuid
|
||||
type UUID struct{}
|
||||
|
||||
// Generate creates a UUID v4 string
|
||||
func (i *UUID) Generate() (string, error) {
|
||||
return uuid.NewV4().String(), nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"id": 5000,
|
||||
"srcID": 5000,
|
||||
"name": "Kapa 1",
|
||||
"url": "http://localhost:9092",
|
||||
"active": true,
|
||||
"organization": "howdy"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"id": "howdy",
|
||||
"name": "An Organization",
|
||||
"defaultRole": "viewer"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"id": "5000",
|
||||
"name": "Influx 1",
|
||||
"username": "user1",
|
||||
"password": "pass1",
|
||||
"url": "http://localhost:8086",
|
||||
"metaUrl": "http://metaurl.com",
|
||||
"type": "influx-enterprise",
|
||||
"insecureSkipVerify": false,
|
||||
"default": true,
|
||||
"telegraf": "telegraf",
|
||||
"sharedSecret": "cubeapples",
|
||||
"organization": "howdy"
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
{
|
||||
"id": 1000,
|
||||
"cells": [
|
||||
{
|
||||
"i": "8f61c619-dd9b-4761-8aa8-577f27247093",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 11,
|
||||
"h": 5,
|
||||
"name": "Untitled Cell",
|
||||
"queries": [
|
||||
{
|
||||
"query": "SELECT mean(\"value\") AS \"mean_value\" FROM \"telegraf\".\"autogen\".\"cpg\" WHERE time \u003e :dashboardTime: GROUP BY :interval: FILL(null)",
|
||||
"queryConfig": {
|
||||
"id": "b20baa61-bacb-4a17-b27d-b904a0d18114",
|
||||
"database": "telegraf",
|
||||
"measurement": "cpg",
|
||||
"retentionPolicy": "autogen",
|
||||
"fields": [
|
||||
{
|
||||
"value": "mean",
|
||||
"type": "func",
|
||||
"alias": "mean_value",
|
||||
"args": [
|
||||
{
|
||||
"value": "value",
|
||||
"type": "field",
|
||||
"alias": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": {},
|
||||
"groupBy": {
|
||||
"time": "auto",
|
||||
"tags": []
|
||||
},
|
||||
"areTagsAccepted": true,
|
||||
"fill": "null",
|
||||
"rawText": null,
|
||||
"range": null,
|
||||
"shifts": []
|
||||
},
|
||||
"source": "/chronograf/v1/sources/2"
|
||||
}
|
||||
],
|
||||
"axes": {
|
||||
"x": {
|
||||
"bounds": [],
|
||||
"label": "",
|
||||
"prefix": "",
|
||||
"suffix": "",
|
||||
"base": "10",
|
||||
"scale": "linear"
|
||||
},
|
||||
"y": {
|
||||
"bounds": [],
|
||||
"label": "",
|
||||
"prefix": "",
|
||||
"suffix": "",
|
||||
"base": "10",
|
||||
"scale": "linear"
|
||||
},
|
||||
"y2": {
|
||||
"bounds": [],
|
||||
"label": "",
|
||||
"prefix": "",
|
||||
"suffix": "",
|
||||
"base": "10",
|
||||
"scale": "linear"
|
||||
}
|
||||
},
|
||||
"type": "line",
|
||||
"colors": [
|
||||
{
|
||||
"id": "0",
|
||||
"type": "min",
|
||||
"hex": "#00C9FF",
|
||||
"name": "laser",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"type": "max",
|
||||
"hex": "#9394FF",
|
||||
"name": "comet",
|
||||
"value": "100"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"tempVar": ":dbs:",
|
||||
"values": [
|
||||
{
|
||||
"value": "_internal",
|
||||
"type": "database",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"value": "telegraf",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "tensorflowdb",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "pushgateway",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "node_exporter",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "mydb",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "tiny",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "blah",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "test",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "chronograf",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "db_name",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "demo",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "eeg",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "solaredge",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"value": "zipkin",
|
||||
"type": "database",
|
||||
"selected": false
|
||||
}
|
||||
],
|
||||
"id": "e7e498bf-5869-4874-9071-24628a2cda63",
|
||||
"type": "databases",
|
||||
"label": "",
|
||||
"query": {
|
||||
"influxql": "SHOW DATABASES",
|
||||
"measurement": "",
|
||||
"tagKey": "",
|
||||
"fieldKey": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "Name This Dashboard",
|
||||
"organization": "howdy"
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/uuid"
|
||||
"github.com/influxdata/chronograf/id"
|
||||
client "github.com/influxdata/kapacitor/client/v1"
|
||||
)
|
||||
|
||||
|
@ -44,7 +44,7 @@ func NewClient(url, username, password string, insecureSkipVerify bool) *Client
|
|||
Username: username,
|
||||
Password: password,
|
||||
InsecureSkipVerify: insecureSkipVerify,
|
||||
ID: &uuid.V4{},
|
||||
ID: &id.UUID{},
|
||||
Ticker: &Alert{},
|
||||
kapaClient: NewKapaClient,
|
||||
}
|
||||
|
|
|
@ -7,9 +7,8 @@ import (
|
|||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// Ensure KapacitorStore and MultiKapacitorStore implements chronograf.ServersStore.
|
||||
// Ensure KapacitorStore implements chronograf.ServersStore.
|
||||
var _ chronograf.ServersStore = &KapacitorStore{}
|
||||
var _ chronograf.ServersStore = &MultiKapacitorStore{}
|
||||
|
||||
// KapacitorStore implements the chronograf.ServersStore interface, and keeps
|
||||
// an in-memory Kapacitor according to startup configuration
|
||||
|
@ -55,90 +54,3 @@ func (store *KapacitorStore) Update(ctx context.Context, kap chronograf.Server)
|
|||
store.Kapacitor = &kap
|
||||
return nil
|
||||
}
|
||||
|
||||
// MultiKapacitorStore implements the chronograf.ServersStore interface, and
|
||||
// delegates to all contained KapacitorStores
|
||||
type MultiKapacitorStore struct {
|
||||
Stores []chronograf.ServersStore
|
||||
}
|
||||
|
||||
// All concatenates the Kapacitors of all contained Stores
|
||||
func (multi *MultiKapacitorStore) All(ctx context.Context) ([]chronograf.Server, error) {
|
||||
all := []chronograf.Server{}
|
||||
kapSet := map[int]struct{}{}
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var kaps []chronograf.Server
|
||||
kaps, err = store.All(ctx)
|
||||
if err != nil {
|
||||
// If this Store is unable to return an array of kapacitors, skip to the
|
||||
// next Store.
|
||||
continue
|
||||
}
|
||||
ok = true // We've received a response from at least one Store
|
||||
for _, kap := range kaps {
|
||||
// Enforce that the kapacitor has a unique ID
|
||||
// If the ID has been seen before, ignore the kapacitor
|
||||
if _, okay := kapSet[kap.ID]; !okay { // We have a new kapacitor
|
||||
kapSet[kap.ID] = struct{}{} // We just care that the ID is unique
|
||||
all = append(all, kap)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// Add the kap to the first responsive Store
|
||||
func (multi *MultiKapacitorStore) Add(ctx context.Context, kap chronograf.Server) (chronograf.Server, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var k chronograf.Server
|
||||
k, err = store.Add(ctx, kap)
|
||||
if err == nil {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Server{}, nil
|
||||
}
|
||||
|
||||
// Delete delegates to all Stores, returns success if one Store is successful
|
||||
func (multi *MultiKapacitorStore) Delete(ctx context.Context, kap chronograf.Server) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Delete(ctx, kap)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get finds the Source by id among all contained Stores
|
||||
func (multi *MultiKapacitorStore) Get(ctx context.Context, id int) (chronograf.Server, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var k chronograf.Server
|
||||
k, err = store.Get(ctx, id)
|
||||
if err == nil {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Server{}, nil
|
||||
}
|
||||
|
||||
// Update the first responsive Store
|
||||
func (multi *MultiKapacitorStore) Update(ctx context.Context, kap chronograf.Server) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Update(ctx, kap)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
func TestInterfaceImplementation(t *testing.T) {
|
||||
var _ chronograf.ServersStore = &KapacitorStore{}
|
||||
var _ chronograf.ServersStore = &MultiKapacitorStore{}
|
||||
}
|
||||
|
||||
func TestKapacitorStoreAll(t *testing.T) {
|
||||
|
|
|
@ -7,95 +7,8 @@ import (
|
|||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// Ensure MultiSourcesStore and SourcesStore implements chronograf.SourcesStore.
|
||||
// Ensure SourcesStore implements chronograf.SourcesStore.
|
||||
var _ chronograf.SourcesStore = &SourcesStore{}
|
||||
var _ chronograf.SourcesStore = &MultiSourcesStore{}
|
||||
|
||||
// MultiSourcesStore delegates to the SourcesStores that compose it
|
||||
type MultiSourcesStore struct {
|
||||
Stores []chronograf.SourcesStore
|
||||
}
|
||||
|
||||
// All concatenates the Sources of all contained Stores
|
||||
func (multi *MultiSourcesStore) All(ctx context.Context) ([]chronograf.Source, error) {
|
||||
all := []chronograf.Source{}
|
||||
sourceSet := map[int]struct{}{}
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var sources []chronograf.Source
|
||||
sources, err = store.All(ctx)
|
||||
if err != nil {
|
||||
// If this Store is unable to return an array of sources, skip to the
|
||||
// next Store.
|
||||
continue
|
||||
}
|
||||
ok = true // We've received a response from at least one Store
|
||||
for _, s := range sources {
|
||||
// Enforce that the source has a unique ID
|
||||
// If the source has been seen before, don't override what we already have
|
||||
if _, okay := sourceSet[s.ID]; !okay { // We have a new Source!
|
||||
sourceSet[s.ID] = struct{}{} // We just care that the ID is unique
|
||||
all = append(all, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// Add the src to the first Store to respond successfully
|
||||
func (multi *MultiSourcesStore) Add(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var s chronograf.Source
|
||||
s, err = store.Add(ctx, src)
|
||||
if err == nil {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Source{}, nil
|
||||
}
|
||||
|
||||
// Delete delegates to all stores, returns success if one Store is successful
|
||||
func (multi *MultiSourcesStore) Delete(ctx context.Context, src chronograf.Source) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Delete(ctx, src)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get finds the Source by id among all contained Stores
|
||||
func (multi *MultiSourcesStore) Get(ctx context.Context, id int) (chronograf.Source, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var s chronograf.Source
|
||||
s, err = store.Get(ctx, id)
|
||||
if err == nil {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Source{}, err
|
||||
}
|
||||
|
||||
// Update the first store to return a successful response
|
||||
func (multi *MultiSourcesStore) Update(ctx context.Context, src chronograf.Source) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Update(ctx, src)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SourcesStore implements the chronograf.SourcesStore interface
|
||||
type SourcesStore struct {
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package multistore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// Ensure DashboardsStore implements chronograf.DashboardsStore.
|
||||
var _ chronograf.DashboardsStore = &DashboardsStore{}
|
||||
|
||||
// DashboardsStore implements the chronograf.DashboardsStore interface, and
|
||||
// delegates to all contained DashboardsStores
|
||||
type DashboardsStore struct {
|
||||
Stores []chronograf.DashboardsStore
|
||||
}
|
||||
|
||||
// All concatenates the Dashboards of all contained Stores
|
||||
func (multi *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) {
|
||||
all := []chronograf.Dashboard{}
|
||||
boardSet := map[chronograf.DashboardID]struct{}{}
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var boards []chronograf.Dashboard
|
||||
boards, err = store.All(ctx)
|
||||
if err != nil {
|
||||
// If this Store is unable to return an array of dashboards, skip to the
|
||||
// next Store.
|
||||
continue
|
||||
}
|
||||
ok = true // We've received a response from at least one Store
|
||||
for _, board := range boards {
|
||||
// Enforce that the dashboard has a unique ID
|
||||
// If the ID has been seen before, ignore the dashboard
|
||||
if _, okay := boardSet[board.ID]; !okay { // We have a new dashboard
|
||||
boardSet[board.ID] = struct{}{} // We just care that the ID is unique
|
||||
all = append(all, board)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// Add the dashboard to the first responsive Store
|
||||
func (multi *DashboardsStore) Add(ctx context.Context, dashboard chronograf.Dashboard) (chronograf.Dashboard, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var d chronograf.Dashboard
|
||||
d, err = store.Add(ctx, dashboard)
|
||||
if err == nil {
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Dashboard{}, nil
|
||||
}
|
||||
|
||||
// Delete delegates to all Stores, returns success if one Store is successful
|
||||
func (multi *DashboardsStore) Delete(ctx context.Context, dashboard chronograf.Dashboard) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Delete(ctx, dashboard)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get finds the Dashboard by id among all contained Stores
|
||||
func (multi *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (chronograf.Dashboard, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var d chronograf.Dashboard
|
||||
d, err = store.Get(ctx, id)
|
||||
if err == nil {
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Dashboard{}, nil
|
||||
}
|
||||
|
||||
// Update the first responsive Store
|
||||
func (multi *DashboardsStore) Update(ctx context.Context, dashboard chronograf.Dashboard) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Update(ctx, dashboard)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package multistore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// Ensure KapacitorStore implements chronograf.ServersStore.
|
||||
var _ chronograf.ServersStore = &KapacitorStore{}
|
||||
|
||||
// KapacitorStore implements the chronograf.ServersStore interface, and
|
||||
// delegates to all contained KapacitorStores
|
||||
type KapacitorStore struct {
|
||||
Stores []chronograf.ServersStore
|
||||
}
|
||||
|
||||
// All concatenates the Kapacitors of all contained Stores
|
||||
func (multi *KapacitorStore) All(ctx context.Context) ([]chronograf.Server, error) {
|
||||
all := []chronograf.Server{}
|
||||
kapSet := map[int]struct{}{}
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var kaps []chronograf.Server
|
||||
kaps, err = store.All(ctx)
|
||||
if err != nil {
|
||||
// If this Store is unable to return an array of kapacitors, skip to the
|
||||
// next Store.
|
||||
continue
|
||||
}
|
||||
ok = true // We've received a response from at least one Store
|
||||
for _, kap := range kaps {
|
||||
// Enforce that the kapacitor has a unique ID
|
||||
// If the ID has been seen before, ignore the kapacitor
|
||||
if _, okay := kapSet[kap.ID]; !okay { // We have a new kapacitor
|
||||
kapSet[kap.ID] = struct{}{} // We just care that the ID is unique
|
||||
all = append(all, kap)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// Add the kap to the first responsive Store
|
||||
func (multi *KapacitorStore) Add(ctx context.Context, kap chronograf.Server) (chronograf.Server, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var k chronograf.Server
|
||||
k, err = store.Add(ctx, kap)
|
||||
if err == nil {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Server{}, nil
|
||||
}
|
||||
|
||||
// Delete delegates to all Stores, returns success if one Store is successful
|
||||
func (multi *KapacitorStore) Delete(ctx context.Context, kap chronograf.Server) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Delete(ctx, kap)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get finds the Source by id among all contained Stores
|
||||
func (multi *KapacitorStore) Get(ctx context.Context, id int) (chronograf.Server, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var k chronograf.Server
|
||||
k, err = store.Get(ctx, id)
|
||||
if err == nil {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Server{}, nil
|
||||
}
|
||||
|
||||
// Update the first responsive Store
|
||||
func (multi *KapacitorStore) Update(ctx context.Context, kap chronograf.Server) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Update(ctx, kap)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package multistore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
func TestInterfaceImplementation(t *testing.T) {
|
||||
var _ chronograf.ServersStore = &KapacitorStore{}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package layouts
|
||||
package multistore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -6,15 +6,15 @@ import (
|
|||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// MultiLayoutsStore is a LayoutsStore that contains multiple LayoutsStores
|
||||
// Layouts is a LayoutsStore that contains multiple LayoutsStores
|
||||
// The All method will return the set of all Layouts.
|
||||
// Each method will be tried against the Stores slice serially.
|
||||
type MultiLayoutsStore struct {
|
||||
type Layouts struct {
|
||||
Stores []chronograf.LayoutsStore
|
||||
}
|
||||
|
||||
// All returns the set of all layouts
|
||||
func (s *MultiLayoutsStore) All(ctx context.Context) ([]chronograf.Layout, error) {
|
||||
func (s *Layouts) All(ctx context.Context) ([]chronograf.Layout, error) {
|
||||
all := []chronograf.Layout{}
|
||||
layoutSet := map[string]chronograf.Layout{}
|
||||
ok := false
|
||||
|
@ -43,7 +43,7 @@ func (s *MultiLayoutsStore) All(ctx context.Context) ([]chronograf.Layout, error
|
|||
}
|
||||
|
||||
// Add creates a new dashboard in the LayoutsStore. Tries each store sequentially until success.
|
||||
func (s *MultiLayoutsStore) Add(ctx context.Context, layout chronograf.Layout) (chronograf.Layout, error) {
|
||||
func (s *Layouts) Add(ctx context.Context, layout chronograf.Layout) (chronograf.Layout, error) {
|
||||
var err error
|
||||
for _, store := range s.Stores {
|
||||
var l chronograf.Layout
|
||||
|
@ -57,7 +57,7 @@ func (s *MultiLayoutsStore) Add(ctx context.Context, layout chronograf.Layout) (
|
|||
|
||||
// Delete the dashboard from the store. Searches through all stores to find Layout and
|
||||
// then deletes from that store.
|
||||
func (s *MultiLayoutsStore) Delete(ctx context.Context, layout chronograf.Layout) error {
|
||||
func (s *Layouts) Delete(ctx context.Context, layout chronograf.Layout) error {
|
||||
var err error
|
||||
for _, store := range s.Stores {
|
||||
err = store.Delete(ctx, layout)
|
||||
|
@ -69,7 +69,7 @@ func (s *MultiLayoutsStore) Delete(ctx context.Context, layout chronograf.Layout
|
|||
}
|
||||
|
||||
// Get retrieves Layout if `ID` exists. Searches through each store sequentially until success.
|
||||
func (s *MultiLayoutsStore) Get(ctx context.Context, ID string) (chronograf.Layout, error) {
|
||||
func (s *Layouts) Get(ctx context.Context, ID string) (chronograf.Layout, error) {
|
||||
var err error
|
||||
for _, store := range s.Stores {
|
||||
var l chronograf.Layout
|
||||
|
@ -82,7 +82,7 @@ func (s *MultiLayoutsStore) Get(ctx context.Context, ID string) (chronograf.Layo
|
|||
}
|
||||
|
||||
// Update the dashboard in the store. Searches through each store sequentially until success.
|
||||
func (s *MultiLayoutsStore) Update(ctx context.Context, layout chronograf.Layout) error {
|
||||
func (s *Layouts) Update(ctx context.Context, layout chronograf.Layout) error {
|
||||
var err error
|
||||
for _, store := range s.Stores {
|
||||
err = store.Update(ctx, layout)
|
|
@ -0,0 +1,129 @@
|
|||
package multistore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// Ensure OrganizationsStore implements chronograf.OrganizationsStore.
|
||||
var _ chronograf.OrganizationsStore = &OrganizationsStore{}
|
||||
|
||||
// OrganizationsStore implements the chronograf.OrganizationsStore interface, and
|
||||
// delegates to all contained OrganizationsStores
|
||||
type OrganizationsStore struct {
|
||||
Stores []chronograf.OrganizationsStore
|
||||
}
|
||||
|
||||
// All concatenates the Organizations of all contained Stores
|
||||
func (multi *OrganizationsStore) All(ctx context.Context) ([]chronograf.Organization, error) {
|
||||
all := []chronograf.Organization{}
|
||||
orgSet := map[string]struct{}{}
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var orgs []chronograf.Organization
|
||||
orgs, err = store.All(ctx)
|
||||
if err != nil {
|
||||
// If this Store is unable to return an array of orgs, skip to the
|
||||
// next Store.
|
||||
continue
|
||||
}
|
||||
ok = true // We've received a response from at least one Store
|
||||
for _, org := range orgs {
|
||||
// Enforce that the org has a unique ID
|
||||
// If the ID has been seen before, ignore the org
|
||||
if _, okay := orgSet[org.ID]; !okay { // We have a new org
|
||||
orgSet[org.ID] = struct{}{} // We just care that the ID is unique
|
||||
all = append(all, org)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// Add the org to the first responsive Store
|
||||
func (multi *OrganizationsStore) Add(ctx context.Context, org *chronograf.Organization) (*chronograf.Organization, error) {
|
||||
errors := []string{}
|
||||
for _, store := range multi.Stores {
|
||||
var o *chronograf.Organization
|
||||
o, err := store.Add(ctx, org)
|
||||
if err == nil {
|
||||
return o, nil
|
||||
}
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
return nil, fmt.Errorf("Unknown error while adding organization: %s", strings.Join(errors, " "))
|
||||
}
|
||||
|
||||
// Delete delegates to all Stores, returns success if one Store is successful
|
||||
func (multi *OrganizationsStore) Delete(ctx context.Context, org *chronograf.Organization) error {
|
||||
errors := []string{}
|
||||
for _, store := range multi.Stores {
|
||||
err := store.Delete(ctx, org)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
return fmt.Errorf("Unknown error while deleting organization: %s", strings.Join(errors, " "))
|
||||
}
|
||||
|
||||
// Get finds the Organization by id among all contained Stores
|
||||
func (multi *OrganizationsStore) Get(ctx context.Context, query chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var o *chronograf.Organization
|
||||
o, err = store.Get(ctx, query)
|
||||
if err == nil {
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
return nil, chronograf.ErrOrganizationNotFound
|
||||
}
|
||||
|
||||
// Update the first responsive Store
|
||||
func (multi *OrganizationsStore) Update(ctx context.Context, org *chronograf.Organization) error {
|
||||
errors := []string{}
|
||||
for _, store := range multi.Stores {
|
||||
err := store.Update(ctx, org)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
return fmt.Errorf("Unknown error while updating organization: %s", strings.Join(errors, " "))
|
||||
}
|
||||
|
||||
// CreateDefault makes a default organization in the first responsive Store
|
||||
func (multi *OrganizationsStore) CreateDefault(ctx context.Context) error {
|
||||
errors := []string{}
|
||||
for _, store := range multi.Stores {
|
||||
err := store.CreateDefault(ctx)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
return fmt.Errorf("Unknown error while creating default organization: %s", strings.Join(errors, " "))
|
||||
}
|
||||
|
||||
// DefaultOrganization returns the first successful DefaultOrganization
|
||||
func (multi *OrganizationsStore) DefaultOrganization(ctx context.Context) (*chronograf.Organization, error) {
|
||||
errors := []string{}
|
||||
for _, store := range multi.Stores {
|
||||
org, err := store.DefaultOrganization(ctx)
|
||||
if err == nil {
|
||||
return org, nil
|
||||
}
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
return nil, fmt.Errorf("Unknown error while getting default organization: %s", strings.Join(errors, " "))
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package multistore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// Ensure SourcesStore implements chronograf.SourcesStore.
|
||||
var _ chronograf.SourcesStore = &SourcesStore{}
|
||||
|
||||
// SourcesStore delegates to the SourcesStores that compose it
|
||||
type SourcesStore struct {
|
||||
Stores []chronograf.SourcesStore
|
||||
}
|
||||
|
||||
// All concatenates the Sources of all contained Stores
|
||||
func (multi *SourcesStore) All(ctx context.Context) ([]chronograf.Source, error) {
|
||||
all := []chronograf.Source{}
|
||||
sourceSet := map[int]struct{}{}
|
||||
|
||||
ok := false
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var sources []chronograf.Source
|
||||
sources, err = store.All(ctx)
|
||||
if err != nil {
|
||||
// If this Store is unable to return an array of sources, skip to the
|
||||
// next Store.
|
||||
continue
|
||||
}
|
||||
ok = true // We've received a response from at least one Store
|
||||
for _, s := range sources {
|
||||
// Enforce that the source has a unique ID
|
||||
// If the source has been seen before, don't override what we already have
|
||||
if _, okay := sourceSet[s.ID]; !okay { // We have a new Source!
|
||||
sourceSet[s.ID] = struct{}{} // We just care that the ID is unique
|
||||
all = append(all, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// Add the src to the first Store to respond successfully
|
||||
func (multi *SourcesStore) Add(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var s chronograf.Source
|
||||
s, err = store.Add(ctx, src)
|
||||
if err == nil {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Source{}, nil
|
||||
}
|
||||
|
||||
// Delete delegates to all stores, returns success if one Store is successful
|
||||
func (multi *SourcesStore) Delete(ctx context.Context, src chronograf.Source) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Delete(ctx, src)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get finds the Source by id among all contained Stores
|
||||
func (multi *SourcesStore) Get(ctx context.Context, id int) (chronograf.Source, error) {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
var s chronograf.Source
|
||||
s, err = store.Get(ctx, id)
|
||||
if err == nil {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return chronograf.Source{}, err
|
||||
}
|
||||
|
||||
// Update the first store to return a successful response
|
||||
func (multi *SourcesStore) Update(ctx context.Context, src chronograf.Source) error {
|
||||
var err error
|
||||
for _, store := range multi.Stores {
|
||||
err = store.Update(ctx, src)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -66,13 +66,13 @@ func (s *OrganizationsStore) All(ctx context.Context) ([]chronograf.Organization
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defaultOrgID := fmt.Sprintf("%d", defaultOrg.ID)
|
||||
defaultOrgID := defaultOrg.ID
|
||||
|
||||
// This filters organizations without allocating
|
||||
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
|
||||
organizations := ds[:0]
|
||||
for _, d := range ds {
|
||||
id := fmt.Sprintf("%d", d.ID)
|
||||
id := d.ID
|
||||
switch id {
|
||||
case s.organization, defaultOrgID:
|
||||
organizations = append(organizations, d)
|
||||
|
@ -117,7 +117,7 @@ func (s *OrganizationsStore) Get(ctx context.Context, q chronograf.OrganizationQ
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%d", d.ID) != s.organization {
|
||||
if d.ID != s.organization {
|
||||
return nil, chronograf.ErrOrganizationNotFound
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ func TestOrganizations_All(t *testing.T) {
|
|||
},
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
}, nil
|
||||
},
|
||||
|
@ -58,7 +58,7 @@ func TestOrganizations_All(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
}, nil
|
||||
},
|
||||
|
@ -66,11 +66,11 @@ func TestOrganizations_All(t *testing.T) {
|
|||
return []chronograf.Organization{
|
||||
{
|
||||
Name: "howdy",
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
},
|
||||
{
|
||||
Name: "doody",
|
||||
ID: 1447,
|
||||
ID: "1447",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
|
@ -83,11 +83,11 @@ func TestOrganizations_All(t *testing.T) {
|
|||
want: []chronograf.Organization{
|
||||
{
|
||||
Name: "howdy",
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
},
|
||||
{
|
||||
Name: "Default",
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -133,7 +133,7 @@ func TestOrganizations_Add(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1229,
|
||||
ID: "1229",
|
||||
Name: "howdy",
|
||||
}, nil
|
||||
},
|
||||
|
@ -193,7 +193,7 @@ func TestOrganizations_Delete(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1229,
|
||||
ID: "1229",
|
||||
Name: "howdy",
|
||||
}, nil
|
||||
},
|
||||
|
@ -203,7 +203,7 @@ func TestOrganizations_Delete(t *testing.T) {
|
|||
organizationID: "1229",
|
||||
ctx: context.Background(),
|
||||
organization: &chronograf.Organization{
|
||||
ID: 1229,
|
||||
ID: "1229",
|
||||
Name: "howdy",
|
||||
},
|
||||
},
|
||||
|
@ -244,7 +244,7 @@ func TestOrganizations_Get(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "howdy",
|
||||
}, nil
|
||||
},
|
||||
|
@ -254,12 +254,12 @@ func TestOrganizations_Get(t *testing.T) {
|
|||
organizationID: "1337",
|
||||
ctx: context.Background(),
|
||||
organization: &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "howdy",
|
||||
},
|
||||
},
|
||||
want: &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "howdy",
|
||||
},
|
||||
},
|
||||
|
@ -305,7 +305,7 @@ func TestOrganizations_Update(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1229,
|
||||
ID: "1229",
|
||||
Name: "doody",
|
||||
}, nil
|
||||
},
|
||||
|
@ -315,7 +315,7 @@ func TestOrganizations_Update(t *testing.T) {
|
|||
organizationID: "1229",
|
||||
ctx: context.Background(),
|
||||
organization: &chronograf.Organization{
|
||||
ID: 1229,
|
||||
ID: "1229",
|
||||
Name: "howdy",
|
||||
},
|
||||
name: "doody",
|
||||
|
|
|
@ -99,19 +99,13 @@ func AuthorizedUser(
|
|||
Error(w, http.StatusForbidden, "User is not authorized", logger)
|
||||
return
|
||||
}
|
||||
p.Organization = fmt.Sprintf("%d", defaultOrg.ID)
|
||||
p.Organization = defaultOrg.ID
|
||||
}
|
||||
|
||||
// validate that the organization exists
|
||||
orgID, err := parseOrganizationID(p.Organization)
|
||||
_, err = store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &p.Organization})
|
||||
if err != nil {
|
||||
log.Error("Failed to validate organization on context")
|
||||
Error(w, http.StatusForbidden, "User is not authorized", logger)
|
||||
return
|
||||
}
|
||||
_, err = store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &orgID})
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Failed to retrieve organization %d from organizations store", orgID))
|
||||
log.Error(fmt.Sprintf("Failed to retrieve organization %s from organizations store", p.Organization))
|
||||
Error(w, http.StatusForbidden, "User is not authorized", logger)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
|
@ -133,7 +133,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -141,7 +141,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -189,7 +189,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -197,7 +197,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -245,7 +245,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -253,7 +253,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -301,7 +301,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -309,7 +309,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -353,7 +353,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -361,7 +361,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -409,7 +409,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -417,7 +417,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -465,7 +465,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -473,7 +473,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -517,7 +517,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -525,7 +525,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -569,7 +569,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -577,7 +577,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -620,7 +620,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -628,7 +628,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -667,7 +667,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -675,7 +675,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -714,7 +714,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -722,7 +722,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -765,7 +765,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -773,7 +773,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -819,7 +819,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -862,7 +862,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -870,7 +870,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -914,7 +914,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -922,7 +922,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -966,7 +966,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -974,7 +974,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1018,7 +1018,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1026,7 +1026,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1071,7 +1071,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1079,7 +1079,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1128,7 +1128,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1136,7 +1136,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1185,7 +1185,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1193,7 +1193,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1242,7 +1242,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1250,7 +1250,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1298,7 +1298,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1306,7 +1306,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1346,7 +1346,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1354,7 +1354,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1397,7 +1397,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1405,7 +1405,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
@ -1449,7 +1449,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1457,9 +1457,9 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
switch *q.ID {
|
||||
case 1338:
|
||||
case "1338":
|
||||
return &chronograf.Organization{
|
||||
ID: 1338,
|
||||
ID: "1338",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
default:
|
||||
|
@ -1511,7 +1511,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -1519,7 +1519,7 @@ func TestAuthorizedUser(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
}, nil
|
||||
},
|
||||
|
|
|
@ -3,27 +3,28 @@ package server
|
|||
import (
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/canned"
|
||||
"github.com/influxdata/chronograf/layouts"
|
||||
"github.com/influxdata/chronograf/filestore"
|
||||
"github.com/influxdata/chronograf/memdb"
|
||||
"github.com/influxdata/chronograf/multistore"
|
||||
)
|
||||
|
||||
// LayoutBuilder is responsible for building Layouts
|
||||
type LayoutBuilder interface {
|
||||
Build(chronograf.LayoutsStore) (*layouts.MultiLayoutsStore, error)
|
||||
Build(chronograf.LayoutsStore) (*multistore.Layouts, error)
|
||||
}
|
||||
|
||||
// MultiLayoutBuilder implements LayoutBuilder and will return a MultiLayoutsStore
|
||||
// MultiLayoutBuilder implements LayoutBuilder and will return a Layouts
|
||||
type MultiLayoutBuilder struct {
|
||||
Logger chronograf.Logger
|
||||
UUID chronograf.ID
|
||||
CannedPath string
|
||||
}
|
||||
|
||||
// Build will construct a MultiLayoutsStore of canned and db-backed personalized
|
||||
// Build will construct a Layouts of canned and db-backed personalized
|
||||
// layouts
|
||||
func (builder *MultiLayoutBuilder) Build(db chronograf.LayoutsStore) (*layouts.MultiLayoutsStore, error) {
|
||||
func (builder *MultiLayoutBuilder) Build(db chronograf.LayoutsStore) (*multistore.Layouts, error) {
|
||||
// These apps are those handled from a directory
|
||||
apps := canned.NewApps(builder.CannedPath, builder.UUID, builder.Logger)
|
||||
apps := filestore.NewApps(builder.CannedPath, builder.UUID, builder.Logger)
|
||||
// These apps are statically compiled into chronograf
|
||||
binApps := &canned.BinLayoutsStore{
|
||||
Logger: builder.Logger,
|
||||
|
@ -31,7 +32,7 @@ func (builder *MultiLayoutBuilder) Build(db chronograf.LayoutsStore) (*layouts.M
|
|||
// 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.
|
||||
layouts := &layouts.MultiLayoutsStore{
|
||||
layouts := &multistore.Layouts{
|
||||
Stores: []chronograf.LayoutsStore{
|
||||
db,
|
||||
apps,
|
||||
|
@ -42,9 +43,38 @@ func (builder *MultiLayoutBuilder) Build(db chronograf.LayoutsStore) (*layouts.M
|
|||
return layouts, nil
|
||||
}
|
||||
|
||||
// DashboardBuilder is responsible for building dashboards
|
||||
type DashboardBuilder interface {
|
||||
Build(chronograf.DashboardsStore) (*multistore.DashboardsStore, error)
|
||||
}
|
||||
|
||||
// MultiDashboardBuilder builds a DashboardsStore backed by bolt and the filesystem
|
||||
type MultiDashboardBuilder struct {
|
||||
Logger chronograf.Logger
|
||||
ID chronograf.ID
|
||||
Path string
|
||||
}
|
||||
|
||||
// Build will construct a Dashboard store of filesystem and db-backed dashboards
|
||||
func (builder *MultiDashboardBuilder) Build(db chronograf.DashboardsStore) (*multistore.DashboardsStore, error) {
|
||||
// These dashboards are those handled from a directory
|
||||
files := filestore.NewDashboards(builder.Path, builder.ID, builder.Logger)
|
||||
// Acts as a front-end to both the bolt dashboard and filesystem dashboards.
|
||||
// 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
|
||||
dashboards := &multistore.DashboardsStore{
|
||||
Stores: []chronograf.DashboardsStore{
|
||||
db,
|
||||
files,
|
||||
},
|
||||
}
|
||||
|
||||
return dashboards, nil
|
||||
}
|
||||
|
||||
// SourcesBuilder builds a MultiSourceStore
|
||||
type SourcesBuilder interface {
|
||||
Build(chronograf.SourcesStore) (*memdb.MultiSourcesStore, error)
|
||||
Build(chronograf.SourcesStore) (*multistore.SourcesStore, error)
|
||||
}
|
||||
|
||||
// MultiSourceBuilder implements SourcesBuilder
|
||||
|
@ -52,11 +82,18 @@ type MultiSourceBuilder struct {
|
|||
InfluxDBURL string
|
||||
InfluxDBUsername string
|
||||
InfluxDBPassword string
|
||||
|
||||
Logger chronograf.Logger
|
||||
ID chronograf.ID
|
||||
Path string
|
||||
}
|
||||
|
||||
// Build will return a MultiSourceStore
|
||||
func (fs *MultiSourceBuilder) Build(db chronograf.SourcesStore) (*memdb.MultiSourcesStore, error) {
|
||||
stores := []chronograf.SourcesStore{db}
|
||||
func (fs *MultiSourceBuilder) Build(db chronograf.SourcesStore) (*multistore.SourcesStore, error) {
|
||||
// These dashboards are those handled from a directory
|
||||
files := filestore.NewSources(fs.Path, fs.ID, fs.Logger)
|
||||
|
||||
stores := []chronograf.SourcesStore{db, files}
|
||||
|
||||
if fs.InfluxDBURL != "" {
|
||||
influxStore := &memdb.SourcesStore{
|
||||
|
@ -71,7 +108,7 @@ func (fs *MultiSourceBuilder) Build(db chronograf.SourcesStore) (*memdb.MultiSou
|
|||
}}
|
||||
stores = append([]chronograf.SourcesStore{influxStore}, stores...)
|
||||
}
|
||||
sources := &memdb.MultiSourcesStore{
|
||||
sources := &multistore.SourcesStore{
|
||||
Stores: stores,
|
||||
}
|
||||
|
||||
|
@ -80,7 +117,7 @@ func (fs *MultiSourceBuilder) Build(db chronograf.SourcesStore) (*memdb.MultiSou
|
|||
|
||||
// KapacitorBuilder builds a KapacitorStore
|
||||
type KapacitorBuilder interface {
|
||||
Build(chronograf.ServersStore) (*memdb.MultiKapacitorStore, error)
|
||||
Build(chronograf.ServersStore) (*multistore.KapacitorStore, error)
|
||||
}
|
||||
|
||||
// MultiKapacitorBuilder implements KapacitorBuilder
|
||||
|
@ -88,11 +125,19 @@ type MultiKapacitorBuilder struct {
|
|||
KapacitorURL string
|
||||
KapacitorUsername string
|
||||
KapacitorPassword string
|
||||
|
||||
Logger chronograf.Logger
|
||||
ID chronograf.ID
|
||||
Path string
|
||||
}
|
||||
|
||||
// Build will return a MultiKapacitorStore
|
||||
func (builder *MultiKapacitorBuilder) Build(db chronograf.ServersStore) (*memdb.MultiKapacitorStore, error) {
|
||||
stores := []chronograf.ServersStore{db}
|
||||
// Build will return a multistore facade KapacitorStore over memdb and bolt
|
||||
func (builder *MultiKapacitorBuilder) Build(db chronograf.ServersStore) (*multistore.KapacitorStore, error) {
|
||||
// These dashboards are those handled from a directory
|
||||
files := filestore.NewKapacitors(builder.Path, builder.ID, builder.Logger)
|
||||
|
||||
stores := []chronograf.ServersStore{db, files}
|
||||
|
||||
if builder.KapacitorURL != "" {
|
||||
memStore := &memdb.KapacitorStore{
|
||||
Kapacitor: &chronograf.Server{
|
||||
|
@ -106,8 +151,36 @@ func (builder *MultiKapacitorBuilder) Build(db chronograf.ServersStore) (*memdb.
|
|||
}
|
||||
stores = append([]chronograf.ServersStore{memStore}, stores...)
|
||||
}
|
||||
kapacitors := &memdb.MultiKapacitorStore{
|
||||
kapacitors := &multistore.KapacitorStore{
|
||||
Stores: stores,
|
||||
}
|
||||
return kapacitors, nil
|
||||
}
|
||||
|
||||
// OrganizationBuilder is responsible for building dashboards
|
||||
type OrganizationBuilder interface {
|
||||
Build(chronograf.OrganizationsStore) (*multistore.OrganizationsStore, error)
|
||||
}
|
||||
|
||||
// MultiOrganizationBuilder builds a OrganizationsStore backed by bolt and the filesystem
|
||||
type MultiOrganizationBuilder struct {
|
||||
Logger chronograf.Logger
|
||||
Path string
|
||||
}
|
||||
|
||||
// Build will construct a Organization store of filesystem and db-backed dashboards
|
||||
func (builder *MultiOrganizationBuilder) Build(db chronograf.OrganizationsStore) (*multistore.OrganizationsStore, error) {
|
||||
// These organization are those handled from a directory
|
||||
files := filestore.NewOrganizations(builder.Path, builder.Logger)
|
||||
// Acts as a front-end to both the bolt org and filesystem orgs.
|
||||
// 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
|
||||
orgs := &multistore.OrganizationsStore{
|
||||
Stores: []chronograf.OrganizationsStore{
|
||||
db,
|
||||
files,
|
||||
},
|
||||
}
|
||||
|
||||
return orgs, nil
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"github.com/bouk/httprouter"
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/uuid"
|
||||
idgen "github.com/influxdata/chronograf/id"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -214,7 +214,7 @@ func (s *Service) NewDashboardCell(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
ids := uuid.V4{}
|
||||
ids := &idgen.UUID{}
|
||||
cid, err := ids.Generate()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error creating cell ID of dashboard %d: %v", id, err)
|
||||
|
|
|
@ -101,7 +101,7 @@ func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := ValidDashboardRequest(&dashboard, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := ValidDashboardRequest(&dashboard, defaultOrg.ID); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ func (s *Service) ReplaceDashboard(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := ValidDashboardRequest(&req, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := ValidDashboardRequest(&req, defaultOrg.ID); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
|
|||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
if err := ValidDashboardRequest(&req, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := ValidDashboardRequest(&req, defaultOrg.ID); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ func (s *Service) NewKapacitor(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := req.Valid(fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := req.Valid(defaultOrg.ID); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
|
32
server/me.go
32
server/me.go
|
@ -96,12 +96,7 @@ func (s *Service) UpdateMe(auth oauth2.Authenticator) func(http.ResponseWriter,
|
|||
}
|
||||
|
||||
// validate that the organization exists
|
||||
orgID, err := parseOrganizationID(req.Organization)
|
||||
if err != nil {
|
||||
Error(w, http.StatusInternalServerError, err.Error(), s.Logger)
|
||||
return
|
||||
}
|
||||
_, err = s.Store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &orgID})
|
||||
_, err = s.Store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &req.Organization})
|
||||
if err != nil {
|
||||
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
|
||||
return
|
||||
|
@ -121,7 +116,7 @@ func (s *Service) UpdateMe(auth oauth2.Authenticator) func(http.ResponseWriter,
|
|||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
p.Organization = fmt.Sprintf("%d", defaultOrg.ID)
|
||||
p.Organization = defaultOrg.ID
|
||||
}
|
||||
scheme, err := getScheme(ctx)
|
||||
if err != nil {
|
||||
|
@ -212,7 +207,7 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
|||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
p.Organization = fmt.Sprintf("%d", defaultOrg.ID)
|
||||
p.Organization = defaultOrg.ID
|
||||
}
|
||||
|
||||
usr, err := s.Store.Users(serverCtx).Get(serverCtx, chronograf.UserQuery{
|
||||
|
@ -236,7 +231,7 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
|||
if defaultOrg.Public || usr.SuperAdmin == true {
|
||||
// If the default organization is public, or the user is a super admin
|
||||
// they will always have a role in the default organization
|
||||
defaultOrgID := fmt.Sprintf("%d", defaultOrg.ID)
|
||||
defaultOrgID := defaultOrg.ID
|
||||
if !hasRoleInDefaultOrganization(usr, defaultOrgID) {
|
||||
usr.Roles = append(usr.Roles, chronograf.Role{
|
||||
Organization: defaultOrgID,
|
||||
|
@ -254,12 +249,7 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
|||
Error(w, http.StatusForbidden, "This organization is private. To gain access, you must be explicitly added by an administrator.", s.Logger)
|
||||
return
|
||||
}
|
||||
orgID, err := parseOrganizationID(p.Organization)
|
||||
if err != nil {
|
||||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
currentOrg, err := s.Store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &orgID})
|
||||
currentOrg, err := s.Store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &p.Organization})
|
||||
if err == chronograf.ErrOrganizationNotFound {
|
||||
// The intent is to force a the user to go through another auth flow
|
||||
Error(w, http.StatusForbidden, "user's current organization was not found", s.Logger)
|
||||
|
@ -301,7 +291,7 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
|||
{
|
||||
Name: defaultOrg.DefaultRole,
|
||||
// This is the ID of the default organization
|
||||
Organization: fmt.Sprintf("%d", defaultOrg.ID),
|
||||
Organization: defaultOrg.ID,
|
||||
},
|
||||
},
|
||||
// TODO(desa): this needs a better name
|
||||
|
@ -320,12 +310,7 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
|||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
orgID, err := parseOrganizationID(p.Organization)
|
||||
if err != nil {
|
||||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
currentOrg, err := s.Store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &orgID})
|
||||
currentOrg, err := s.Store.Organizations(serverCtx).Get(serverCtx, chronograf.OrganizationQuery{ID: &p.Organization})
|
||||
if err != nil {
|
||||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
|
@ -376,8 +361,7 @@ func (s *Service) usersOrganizations(ctx context.Context, u *chronograf.User) ([
|
|||
|
||||
orgs := []chronograf.Organization{}
|
||||
for orgID, _ := range orgIDs {
|
||||
id, err := parseOrganizationID(orgID)
|
||||
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
|
||||
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &orgID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: false,
|
||||
|
@ -67,16 +67,16 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: false,
|
||||
}, nil
|
||||
case 1:
|
||||
case "1":
|
||||
return &chronograf.Organization{
|
||||
ID: 1,
|
||||
ID: "1",
|
||||
Name: "The Bad Place",
|
||||
Public: false,
|
||||
}, nil
|
||||
|
@ -124,7 +124,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: false,
|
||||
|
@ -132,16 +132,16 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
}, nil
|
||||
case 1:
|
||||
case "1":
|
||||
return &chronograf.Organization{
|
||||
ID: 1,
|
||||
ID: "1",
|
||||
Name: "The Bad Place",
|
||||
Public: true,
|
||||
}, nil
|
||||
|
@ -190,7 +190,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: false,
|
||||
|
@ -198,16 +198,16 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
}, nil
|
||||
case 1:
|
||||
case "1":
|
||||
return &chronograf.Organization{
|
||||
ID: 1,
|
||||
ID: "1",
|
||||
Name: "The Bad Place",
|
||||
Public: true,
|
||||
}, nil
|
||||
|
@ -255,7 +255,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -263,16 +263,16 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
}, nil
|
||||
case 1:
|
||||
case "1":
|
||||
return &chronograf.Organization{
|
||||
ID: 1,
|
||||
ID: "1",
|
||||
Name: "The Bad Place",
|
||||
Public: true,
|
||||
}, nil
|
||||
|
@ -320,7 +320,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -328,9 +328,9 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -383,7 +383,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Gnarly Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -391,7 +391,7 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Gnarly Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -445,7 +445,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Gnarly Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -453,7 +453,7 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Gnarly Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -507,7 +507,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Gnarly Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -515,7 +515,7 @@ func TestService_Me(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Gnarly Default",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -568,13 +568,13 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Public: true,
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Bad Place",
|
||||
Public: true,
|
||||
}, nil
|
||||
|
@ -662,7 +662,7 @@ func TestService_Me(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Bad Place",
|
||||
DefaultRole: roles.MemberRoleName,
|
||||
Public: false,
|
||||
|
@ -789,7 +789,7 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.AdminRoleName,
|
||||
Public: true,
|
||||
|
@ -800,16 +800,16 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
switch *q.ID {
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.AdminRoleName,
|
||||
Public: true,
|
||||
}, nil
|
||||
case 1337:
|
||||
case "1337":
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
Public: true,
|
||||
}, nil
|
||||
|
@ -863,7 +863,7 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.EditorRoleName,
|
||||
Public: true,
|
||||
|
@ -874,15 +874,15 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
switch *q.ID {
|
||||
case 1337:
|
||||
case "1337":
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ThrillShilliettos",
|
||||
Public: false,
|
||||
}, nil
|
||||
case 0:
|
||||
case "0":
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "Default",
|
||||
DefaultRole: roles.EditorRoleName,
|
||||
Public: true,
|
||||
|
@ -938,7 +938,7 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
@ -946,7 +946,7 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
return nil, fmt.Errorf("Invalid organization query: missing ID")
|
||||
}
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The ShillBillThrilliettas",
|
||||
Public: true,
|
||||
}, nil
|
||||
|
@ -999,7 +999,7 @@ func TestService_UpdateMe(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
}, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/bouk/httprouter"
|
||||
"github.com/influxdata/chronograf"
|
||||
|
@ -13,10 +12,6 @@ import (
|
|||
"github.com/influxdata/chronograf/roles"
|
||||
)
|
||||
|
||||
func parseOrganizationID(id string) (uint64, error) {
|
||||
return strconv.ParseUint(id, 10, 64)
|
||||
}
|
||||
|
||||
type organizationRequest struct {
|
||||
Name string `json:"name"`
|
||||
DefaultRole string `json:"defaultRole"`
|
||||
|
@ -68,7 +63,7 @@ func newOrganizationResponse(o *chronograf.Organization) *organizationResponse {
|
|||
return &organizationResponse{
|
||||
Organization: *o,
|
||||
Links: selfLinks{
|
||||
Self: fmt.Sprintf("/chronograf/v1/organizations/%d", o.ID),
|
||||
Self: fmt.Sprintf("/chronograf/v1/organizations/%s", o.ID),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -144,15 +139,14 @@ func (s *Service) NewOrganization(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
orgID := fmt.Sprintf("%d", res.ID)
|
||||
user.Roles = []chronograf.Role{
|
||||
{
|
||||
Organization: orgID,
|
||||
Organization: res.ID,
|
||||
Name: roles.AdminRoleName,
|
||||
},
|
||||
}
|
||||
|
||||
orgCtx := context.WithValue(ctx, organizations.ContextKey, orgID)
|
||||
orgCtx := context.WithValue(ctx, organizations.ContextKey, res.ID)
|
||||
_, err = s.Store.Users(orgCtx).Add(orgCtx, user)
|
||||
if err != nil {
|
||||
// Best attempt at cleanup the organization if there were any errors adding user to org
|
||||
|
@ -171,12 +165,7 @@ func (s *Service) NewOrganization(w http.ResponseWriter, r *http.Request) {
|
|||
func (s *Service) OrganizationID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
idStr := httprouter.GetParamFromContext(ctx, "id")
|
||||
id, err := parseOrganizationID(idStr)
|
||||
if err != nil {
|
||||
Error(w, http.StatusBadRequest, fmt.Sprintf("invalid organization id: %s", err.Error()), s.Logger)
|
||||
return
|
||||
}
|
||||
id := httprouter.GetParamFromContext(ctx, "id")
|
||||
|
||||
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
|
||||
if err != nil {
|
||||
|
@ -202,12 +191,7 @@ func (s *Service) UpdateOrganization(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
ctx := r.Context()
|
||||
idStr := httprouter.GetParamFromContext(ctx, "id")
|
||||
id, err := parseOrganizationID(idStr)
|
||||
if err != nil {
|
||||
Error(w, http.StatusBadRequest, fmt.Sprintf("invalid organization id: %s", err.Error()), s.Logger)
|
||||
return
|
||||
}
|
||||
id := httprouter.GetParamFromContext(ctx, "id")
|
||||
|
||||
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
|
||||
if err != nil {
|
||||
|
@ -242,12 +226,7 @@ func (s *Service) UpdateOrganization(w http.ResponseWriter, r *http.Request) {
|
|||
// RemoveOrganization removes an organization in the organizations store
|
||||
func (s *Service) RemoveOrganization(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
idStr := httprouter.GetParamFromContext(ctx, "id")
|
||||
id, err := parseOrganizationID(idStr)
|
||||
if err != nil {
|
||||
Error(w, http.StatusBadRequest, fmt.Sprintf("invalid organization id: %s", err.Error()), s.Logger)
|
||||
return
|
||||
}
|
||||
id := httprouter.GetParamFromContext(ctx, "id")
|
||||
|
||||
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
|
||||
if err != nil {
|
||||
|
|
|
@ -50,9 +50,9 @@ func TestService_OrganizationID(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 1337:
|
||||
case "1337":
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
Public: false,
|
||||
}, nil
|
||||
|
@ -139,12 +139,12 @@ func TestService_Organizations(t *testing.T) {
|
|||
AllF: func(ctx context.Context) ([]chronograf.Organization, error) {
|
||||
return []chronograf.Organization{
|
||||
chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
Public: false,
|
||||
},
|
||||
chronograf.Organization{
|
||||
ID: 100,
|
||||
ID: "100",
|
||||
Name: "The Bad Place",
|
||||
Public: false,
|
||||
},
|
||||
|
@ -228,7 +228,7 @@ func TestService_UpdateOrganization(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: false,
|
||||
|
@ -262,7 +262,7 @@ func TestService_UpdateOrganization(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 0,
|
||||
ID: "0",
|
||||
Name: "The Good Place",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -294,7 +294,7 @@ func TestService_UpdateOrganization(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
DefaultRole: roles.ViewerRoleName,
|
||||
Public: true,
|
||||
|
@ -328,7 +328,7 @@ func TestService_UpdateOrganization(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
DefaultRole: roles.MemberRoleName,
|
||||
Public: false,
|
||||
|
@ -475,9 +475,9 @@ func TestService_RemoveOrganization(t *testing.T) {
|
|||
},
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
switch *q.ID {
|
||||
case 1337:
|
||||
case "1337":
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
}, nil
|
||||
default:
|
||||
|
@ -573,7 +573,7 @@ func TestService_NewOrganization(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
AddF: func(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
Public: false,
|
||||
}, nil
|
||||
|
@ -612,7 +612,7 @@ func TestService_NewOrganization(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
AddF: func(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
}, nil
|
||||
},
|
||||
|
@ -654,7 +654,7 @@ func TestService_NewOrganization(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
AddF: func(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "The Good Place",
|
||||
}, nil
|
||||
},
|
||||
|
|
100
server/server.go
100
server/server.go
|
@ -16,10 +16,10 @@ import (
|
|||
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/bolt"
|
||||
idgen "github.com/influxdata/chronograf/id"
|
||||
"github.com/influxdata/chronograf/influx"
|
||||
clog "github.com/influxdata/chronograf/log"
|
||||
"github.com/influxdata/chronograf/oauth2"
|
||||
"github.com/influxdata/chronograf/uuid"
|
||||
client "github.com/influxdata/usage-client/v1"
|
||||
flags "github.com/jessevdk/go-flags"
|
||||
"github.com/tylerb/graceful"
|
||||
|
@ -54,7 +54,7 @@ type Server struct {
|
|||
|
||||
Develop bool `short:"d" long:"develop" description:"Run server in develop mode."`
|
||||
BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (e.g. './chronograf-v1.db')" env:"BOLT_PATH" default:"chronograf-v1.db"`
|
||||
CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts (/usr/share/chronograf/canned)" env:"CANNED_PATH" default:"canned"`
|
||||
CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned dashboards and application layouts (/usr/share/chronograf/canned)" env:"CANNED_PATH" default:"canned"`
|
||||
TokenSecret string `short:"t" long:"token-secret" description:"Secret to sign tokens" env:"TOKEN_SECRET"`
|
||||
AuthDuration time.Duration `long:"auth-duration" default:"720h" description:"Total duration of cookie life for authentication (in hours). 0 means authentication expires on browser close." env:"AUTH_DURATION"`
|
||||
|
||||
|
@ -122,6 +122,7 @@ func (s *Server) UseHeroku() bool {
|
|||
return s.TokenSecret != "" && s.HerokuClientID != "" && s.HerokuSecret != ""
|
||||
}
|
||||
|
||||
// UseAuth0 validates the CLI parameters to enable Auth0 oauth support
|
||||
func (s *Server) UseAuth0() bool {
|
||||
return s.Auth0ClientID != "" && s.Auth0ClientSecret != ""
|
||||
}
|
||||
|
@ -269,24 +270,52 @@ func (s *Server) NewListener() (net.Listener, error) {
|
|||
return listener, nil
|
||||
}
|
||||
|
||||
type builders struct {
|
||||
Layouts LayoutBuilder
|
||||
Sources SourcesBuilder
|
||||
Kapacitors KapacitorBuilder
|
||||
Dashboards DashboardBuilder
|
||||
Organizations OrganizationBuilder
|
||||
}
|
||||
|
||||
func (s *Server) newBuilders(logger chronograf.Logger) builders {
|
||||
return builders{
|
||||
Layouts: &MultiLayoutBuilder{
|
||||
Logger: logger,
|
||||
UUID: &idgen.UUID{},
|
||||
CannedPath: s.CannedPath,
|
||||
},
|
||||
Dashboards: &MultiDashboardBuilder{
|
||||
Logger: logger,
|
||||
ID: idgen.NewTime(),
|
||||
Path: s.CannedPath,
|
||||
},
|
||||
Sources: &MultiSourceBuilder{
|
||||
InfluxDBURL: s.InfluxDBURL,
|
||||
InfluxDBUsername: s.InfluxDBUsername,
|
||||
InfluxDBPassword: s.InfluxDBPassword,
|
||||
Logger: logger,
|
||||
ID: idgen.NewTime(),
|
||||
Path: s.CannedPath,
|
||||
},
|
||||
Kapacitors: &MultiKapacitorBuilder{
|
||||
KapacitorURL: s.KapacitorURL,
|
||||
KapacitorUsername: s.KapacitorUsername,
|
||||
KapacitorPassword: s.KapacitorPassword,
|
||||
Logger: logger,
|
||||
ID: idgen.NewTime(),
|
||||
Path: s.CannedPath,
|
||||
},
|
||||
Organizations: &MultiOrganizationBuilder{
|
||||
Logger: logger,
|
||||
Path: s.CannedPath,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Serve starts and runs the chronograf server
|
||||
func (s *Server) Serve(ctx context.Context) error {
|
||||
logger := clog.New(clog.ParseLevel(s.LogLevel))
|
||||
layoutBuilder := &MultiLayoutBuilder{
|
||||
Logger: logger,
|
||||
UUID: &uuid.V4{},
|
||||
CannedPath: s.CannedPath,
|
||||
}
|
||||
sourcesBuilder := &MultiSourceBuilder{
|
||||
InfluxDBURL: s.InfluxDBURL,
|
||||
InfluxDBUsername: s.InfluxDBUsername,
|
||||
InfluxDBPassword: s.InfluxDBPassword,
|
||||
}
|
||||
kapacitorBuilder := &MultiKapacitorBuilder{
|
||||
KapacitorURL: s.KapacitorURL,
|
||||
KapacitorUsername: s.KapacitorUsername,
|
||||
KapacitorPassword: s.KapacitorPassword,
|
||||
}
|
||||
_, err := NewCustomLinks(s.CustomLinks)
|
||||
if err != nil {
|
||||
logger.
|
||||
|
@ -295,7 +324,7 @@ func (s *Server) Serve(ctx context.Context) error {
|
|||
Error(err)
|
||||
return err
|
||||
}
|
||||
service := openService(ctx, s, layoutBuilder, sourcesBuilder, kapacitorBuilder, logger)
|
||||
service := openService(ctx, s.BuildInfo, s.BoltPath, s.newBuilders(logger), logger, s.useAuth())
|
||||
if err := service.HandleNewSources(ctx, s.NewSources); err != nil {
|
||||
logger.
|
||||
WithField("component", "server").
|
||||
|
@ -390,18 +419,18 @@ func (s *Server) Serve(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func openService(ctx context.Context, s *Server, lBuilder LayoutBuilder, sBuilder SourcesBuilder, kapBuilder KapacitorBuilder, logger chronograf.Logger) Service {
|
||||
func openService(ctx context.Context, buildInfo chronograf.BuildInfo, boltPath string, builder builders, logger chronograf.Logger, useAuth bool) Service {
|
||||
db := bolt.NewClient()
|
||||
db.Path = s.BoltPath
|
||||
db.Path = boltPath
|
||||
|
||||
if err := db.Open(ctx, logger, s.BuildInfo, bolt.WithBackup()); err != nil {
|
||||
if err := db.Open(ctx, logger, buildInfo, bolt.WithBackup()); err != nil {
|
||||
logger.
|
||||
WithField("component", "boltstore").
|
||||
Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
layouts, err := lBuilder.Build(db.LayoutsStore)
|
||||
layouts, err := builder.Layouts.Build(db.LayoutsStore)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("component", "LayoutsStore").
|
||||
|
@ -409,7 +438,14 @@ func openService(ctx context.Context, s *Server, lBuilder LayoutBuilder, sBuilde
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
sources, err := sBuilder.Build(db.SourcesStore)
|
||||
dashboards, err := builder.Dashboards.Build(db.DashboardsStore)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("component", "DashboardsStore").
|
||||
Error("Unable to construct a MultiDashboardsStore", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
sources, err := builder.Sources.Build(db.SourcesStore)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("component", "SourcesStore").
|
||||
|
@ -417,7 +453,7 @@ func openService(ctx context.Context, s *Server, lBuilder LayoutBuilder, sBuilde
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
kapacitors, err := kapBuilder.Build(db.ServersStore)
|
||||
kapacitors, err := builder.Kapacitors.Build(db.ServersStore)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("component", "KapacitorStore").
|
||||
|
@ -425,19 +461,27 @@ func openService(ctx context.Context, s *Server, lBuilder LayoutBuilder, sBuilde
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
organizations, err := builder.Organizations.Build(db.OrganizationsStore)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("component", "OrganizationsStore").
|
||||
Error("Unable to construct a MultiOrganizationStore", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return Service{
|
||||
TimeSeriesClient: &InfluxClient{},
|
||||
Store: &Store{
|
||||
LayoutsStore: layouts,
|
||||
DashboardsStore: dashboards,
|
||||
SourcesStore: sources,
|
||||
ServersStore: kapacitors,
|
||||
OrganizationsStore: organizations,
|
||||
UsersStore: db.UsersStore,
|
||||
OrganizationsStore: db.OrganizationsStore,
|
||||
LayoutsStore: layouts,
|
||||
DashboardsStore: db.DashboardsStore,
|
||||
ConfigStore: db.ConfigStore,
|
||||
},
|
||||
Logger: logger,
|
||||
UseAuth: s.useAuth(),
|
||||
UseAuth: useAuth,
|
||||
Databases: &influx.Client{Logger: logger},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ func (s *Service) NewSource(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := ValidSourceRequest(&src, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := ValidSourceRequest(&src, defaultOrg.ID); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ func (s *Service) UpdateSource(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := ValidSourceRequest(&src, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := ValidSourceRequest(&src, defaultOrg.ID); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ func (s *Service) HandleNewSources(ctx context.Context, input string) error {
|
|||
}
|
||||
|
||||
for _, sk := range srcsKaps {
|
||||
if err := ValidSourceRequest(&sk.Source, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
if err := ValidSourceRequest(&sk.Source, defaultOrg.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
// Add any new sources and kapacitors as specified via server flag
|
||||
|
|
|
@ -237,7 +237,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
OrganizationsStore chronograf.OrganizationsStore
|
||||
}
|
||||
type args struct {
|
||||
orgID uint64
|
||||
orgID string
|
||||
serverContext bool
|
||||
organization string
|
||||
user *chronograf.User
|
||||
|
@ -259,7 +259,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "21",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
}, nil
|
||||
|
@ -268,11 +268,11 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
},
|
||||
args: args{
|
||||
serverContext: true,
|
||||
orgID: 21,
|
||||
orgID: "21",
|
||||
},
|
||||
wants: wants{
|
||||
organization: &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "21",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
},
|
||||
|
@ -284,7 +284,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "21",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
}, nil
|
||||
|
@ -299,11 +299,11 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
Scheme: "oauth2",
|
||||
SuperAdmin: true,
|
||||
},
|
||||
orgID: 21,
|
||||
orgID: "21",
|
||||
},
|
||||
wants: wants{
|
||||
organization: &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "21",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
},
|
||||
|
@ -315,7 +315,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "21",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
}, nil
|
||||
|
@ -329,7 +329,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
Provider: "github",
|
||||
Scheme: "oauth2",
|
||||
},
|
||||
orgID: 21,
|
||||
orgID: "21",
|
||||
},
|
||||
wants: wants{
|
||||
err: true,
|
||||
|
@ -341,7 +341,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "22",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
}, nil
|
||||
|
@ -355,12 +355,12 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
Provider: "github",
|
||||
Scheme: "oauth2",
|
||||
},
|
||||
organization: "21",
|
||||
orgID: 21,
|
||||
organization: "22",
|
||||
orgID: "22",
|
||||
},
|
||||
wants: wants{
|
||||
organization: &chronograf.Organization{
|
||||
ID: 21,
|
||||
ID: "22",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
},
|
||||
|
@ -372,7 +372,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
OrganizationsStore: &mocks.OrganizationsStore{
|
||||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||
return &chronograf.Organization{
|
||||
ID: 22,
|
||||
ID: "22",
|
||||
Name: "my sweet name",
|
||||
DefaultRole: "viewer",
|
||||
}, nil
|
||||
|
@ -387,7 +387,7 @@ func TestStore_OrganizationsAdd(t *testing.T) {
|
|||
Scheme: "oauth2",
|
||||
},
|
||||
organization: "21",
|
||||
orgID: 21,
|
||||
orgID: "21",
|
||||
},
|
||||
wants: wants{
|
||||
err: true,
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"github.com/bouk/httprouter"
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/uuid"
|
||||
idgen "github.com/influxdata/chronograf/id"
|
||||
)
|
||||
|
||||
// ValidTemplateRequest checks if the request sent to the server is the correct format.
|
||||
|
@ -111,7 +111,7 @@ func (s *Service) NewTemplate(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
ids := uuid.V4{}
|
||||
ids := idgen.UUID{}
|
||||
tid, err := ids.Generate()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error creating template ID for dashboard %d: %v", id, err)
|
||||
|
|
|
@ -54,9 +54,6 @@ func (r *userRequest) ValidRoles() error {
|
|||
if r.Organization == "" {
|
||||
return fmt.Errorf("no organization was provided")
|
||||
}
|
||||
if _, err := parseOrganizationID(r.Organization); err != nil {
|
||||
return fmt.Errorf("failed to parse organization ID: %v", err)
|
||||
}
|
||||
if _, ok := orgs[r.Organization]; ok {
|
||||
return fmt.Errorf("duplicate organization %q in roles", r.Organization)
|
||||
}
|
||||
|
|
|
@ -1156,25 +1156,6 @@ func TestUserRequest_ValidCreate(t *testing.T) {
|
|||
wantErr: false,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Invalid - bad organization",
|
||||
args: args{
|
||||
u: &userRequest{
|
||||
ID: 1337,
|
||||
Name: "billietta",
|
||||
Provider: "auth0",
|
||||
Scheme: "oauth2",
|
||||
Roles: []chronograf.Role{
|
||||
{
|
||||
Name: roles.EditorRoleName,
|
||||
Organization: "l", // this is the character L not integer One
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
err: fmt.Errorf("failed to parse organization ID: strconv.ParseUint: parsing \"l\": invalid syntax"),
|
||||
},
|
||||
{
|
||||
name: "Invalid – Name missing",
|
||||
args: args{
|
||||
|
@ -1319,25 +1300,6 @@ func TestUserRequest_ValidUpdate(t *testing.T) {
|
|||
wantErr: true,
|
||||
err: fmt.Errorf("No Roles to update"),
|
||||
},
|
||||
{
|
||||
name: "Invalid - bad organization",
|
||||
args: args{
|
||||
u: &userRequest{
|
||||
ID: 1337,
|
||||
Name: "billietta",
|
||||
Provider: "auth0",
|
||||
Scheme: "oauth2",
|
||||
Roles: []chronograf.Role{
|
||||
{
|
||||
Name: roles.EditorRoleName,
|
||||
Organization: "l", // this is the character L not integer One
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
err: fmt.Errorf("failed to parse organization ID: strconv.ParseUint: parsing \"l\": invalid syntax"),
|
||||
},
|
||||
{
|
||||
name: "Invalid - bad role name",
|
||||
args: args{
|
||||
|
|
|
@ -12,4 +12,4 @@ export const USER_ROLES = [
|
|||
{name: ADMIN_ROLE},
|
||||
]
|
||||
|
||||
export const DEFAULT_ORG_ID = '0'
|
||||
export const DEFAULT_ORG_ID = 'default'
|
||||
|
|
11
uuid/v4.go
11
uuid/v4.go
|
@ -1,11 +0,0 @@
|
|||
package uuid
|
||||
|
||||
import uuid "github.com/satori/go.uuid"
|
||||
|
||||
// V4 implements chronograf.ID
|
||||
type V4 struct{}
|
||||
|
||||
// Generate creates a UUID v4 string
|
||||
func (i *V4) Generate() (string, error) {
|
||||
return uuid.NewV4().String(), nil
|
||||
}
|
Loading…
Reference in New Issue