Merge branch 'multitenancy' into multitenancy_reset_current_org
commit
bbe1330cbf
|
@ -125,12 +125,11 @@ func MarshalLayout(l chronograf.Layout) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
return proto.Marshal(&Layout{
|
||||
ID: l.ID,
|
||||
Measurement: l.Measurement,
|
||||
Application: l.Application,
|
||||
Autoflow: l.Autoflow,
|
||||
Cells: cells,
|
||||
Organization: l.Organization,
|
||||
ID: l.ID,
|
||||
Measurement: l.Measurement,
|
||||
Application: l.Application,
|
||||
Autoflow: l.Autoflow,
|
||||
Cells: cells,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -145,7 +144,6 @@ func UnmarshalLayout(data []byte, l *chronograf.Layout) error {
|
|||
l.Measurement = pb.Measurement
|
||||
l.Application = pb.Application
|
||||
l.Autoflow = pb.Autoflow
|
||||
l.Organization = pb.Organization
|
||||
cells := make([]chronograf.Cell, len(pb.Cells))
|
||||
for i, c := range pb.Cells {
|
||||
queries := make([]chronograf.Query, len(c.Queries))
|
||||
|
|
|
@ -208,12 +208,11 @@ func (*Server) ProtoMessage() {}
|
|||
func (*Server) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{7} }
|
||||
|
||||
type Layout struct {
|
||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Application string `protobuf:"bytes,2,opt,name=Application,proto3" json:"Application,omitempty"`
|
||||
Measurement string `protobuf:"bytes,3,opt,name=Measurement,proto3" json:"Measurement,omitempty"`
|
||||
Cells []*Cell `protobuf:"bytes,4,rep,name=Cells" json:"Cells,omitempty"`
|
||||
Autoflow bool `protobuf:"varint,5,opt,name=Autoflow,proto3" json:"Autoflow,omitempty"`
|
||||
Organization string `protobuf:"bytes,6,opt,name=Organization,proto3" json:"Organization,omitempty"`
|
||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Application string `protobuf:"bytes,2,opt,name=Application,proto3" json:"Application,omitempty"`
|
||||
Measurement string `protobuf:"bytes,3,opt,name=Measurement,proto3" json:"Measurement,omitempty"`
|
||||
Cells []*Cell `protobuf:"bytes,4,rep,name=Cells" json:"Cells,omitempty"`
|
||||
Autoflow bool `protobuf:"varint,5,opt,name=Autoflow,proto3" json:"Autoflow,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Layout) Reset() { *m = Layout{} }
|
||||
|
@ -391,81 +390,81 @@ func init() {
|
|||
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
||||
|
||||
var fileDescriptorInternal = []byte{
|
||||
// 1211 bytes of a gzipped FileDescriptorProto
|
||||
// 1207 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0x5f, 0x8f, 0xdb, 0x44,
|
||||
0x10, 0xd7, 0xc6, 0x71, 0x12, 0x4f, 0xae, 0x05, 0x2d, 0x15, 0x35, 0x45, 0x42, 0xc1, 0x02, 0xe9,
|
||||
0x10, 0xd7, 0xc6, 0x71, 0x62, 0x4f, 0xae, 0x05, 0x2d, 0x15, 0x35, 0x45, 0x42, 0xc1, 0x02, 0xe9,
|
||||
0x10, 0xf4, 0x40, 0xad, 0x90, 0x10, 0x0f, 0x48, 0xb9, 0x0b, 0xaa, 0x8e, 0xfe, 0xbb, 0x6e, 0x7a,
|
||||
0xe5, 0x09, 0x55, 0x1b, 0x67, 0x72, 0xb1, 0xea, 0xd8, 0x66, 0x6d, 0xdf, 0xc5, 0x7c, 0x1b, 0x24,
|
||||
0x9e, 0x78, 0x44, 0xbc, 0x23, 0xf1, 0x84, 0xf8, 0x20, 0x7c, 0x05, 0x5e, 0xd1, 0xec, 0xae, 0x1d,
|
||||
0xa7, 0x09, 0x55, 0x5f, 0xe0, 0x6d, 0x7f, 0x33, 0xeb, 0xd9, 0x9d, 0x99, 0xdf, 0xfc, 0xbc, 0x70,
|
||||
0x3d, 0x4a, 0x0a, 0x54, 0x89, 0x8c, 0x8f, 0x32, 0x95, 0x16, 0x29, 0x1f, 0xd4, 0x38, 0xf8, 0xab,
|
||||
0x03, 0xbd, 0x69, 0x5a, 0xaa, 0x10, 0xf9, 0x75, 0xe8, 0x9c, 0x4e, 0x7c, 0x36, 0x62, 0x87, 0x8e,
|
||||
0xe8, 0x9c, 0x4e, 0x38, 0x87, 0xee, 0x23, 0xb9, 0x42, 0xbf, 0x33, 0x62, 0x87, 0x9e, 0xd0, 0x6b,
|
||||
0xb2, 0x3d, 0xad, 0x32, 0xf4, 0x1d, 0x63, 0xa3, 0x35, 0xbf, 0x05, 0x83, 0xf3, 0x9c, 0xa2, 0xad,
|
||||
0xd0, 0xef, 0x6a, 0x7b, 0x83, 0xc9, 0x77, 0x26, 0xf3, 0xfc, 0x2a, 0x55, 0x73, 0xdf, 0x35, 0xbe,
|
||||
0x1a, 0xf3, 0x37, 0xc1, 0x39, 0x17, 0x0f, 0xfc, 0x9e, 0x36, 0xd3, 0x92, 0xfb, 0xd0, 0x9f, 0xe0,
|
||||
0x42, 0x96, 0x71, 0xe1, 0xf7, 0x47, 0xec, 0x70, 0x20, 0x6a, 0x48, 0x71, 0x9e, 0x62, 0x8c, 0x17,
|
||||
0x4a, 0x2e, 0xfc, 0x81, 0x89, 0x53, 0x63, 0x7e, 0x04, 0xfc, 0x34, 0xc9, 0x31, 0x2c, 0x15, 0x4e,
|
||||
0x5f, 0x44, 0xd9, 0x33, 0x54, 0xd1, 0xa2, 0xf2, 0x3d, 0x1d, 0x60, 0x8f, 0x87, 0x4e, 0x79, 0x88,
|
||||
0x85, 0xa4, 0xb3, 0x41, 0x87, 0xaa, 0x21, 0x0f, 0xe0, 0x60, 0xba, 0x94, 0x0a, 0xe7, 0x53, 0x0c,
|
||||
0x15, 0x16, 0xfe, 0x50, 0xbb, 0xb7, 0x6c, 0xb4, 0xe7, 0xb1, 0xba, 0x90, 0x49, 0xf4, 0x83, 0x2c,
|
||||
0xa2, 0x34, 0xf1, 0x0f, 0xcc, 0x9e, 0xb6, 0x8d, 0xaa, 0x24, 0xd2, 0x18, 0xfd, 0x6b, 0xa6, 0x4a,
|
||||
0xb4, 0x0e, 0x7e, 0x65, 0xe0, 0x4d, 0x64, 0xbe, 0x9c, 0xa5, 0x52, 0xcd, 0x5f, 0xab, 0xd6, 0xb7,
|
||||
0xc1, 0x0d, 0x31, 0x8e, 0x73, 0xdf, 0x19, 0x39, 0x87, 0xc3, 0x3b, 0x37, 0x8f, 0x9a, 0x26, 0x36,
|
||||
0x71, 0x4e, 0x30, 0x8e, 0x85, 0xd9, 0xc5, 0x3f, 0x03, 0xaf, 0xc0, 0x55, 0x16, 0xcb, 0x02, 0x73,
|
||||
0xbf, 0xab, 0x3f, 0xe1, 0x9b, 0x4f, 0x9e, 0x5a, 0x97, 0xd8, 0x6c, 0xda, 0x49, 0xc5, 0xdd, 0x4d,
|
||||
0x25, 0xf8, 0xb9, 0x03, 0xd7, 0xb6, 0x8e, 0xe3, 0x07, 0xc0, 0xd6, 0xfa, 0xe6, 0xae, 0x60, 0x6b,
|
||||
0x42, 0x95, 0xbe, 0xb5, 0x2b, 0x58, 0x45, 0xe8, 0x4a, 0x73, 0xc3, 0x15, 0xec, 0x8a, 0xd0, 0x52,
|
||||
0x33, 0xc2, 0x15, 0x6c, 0xc9, 0x3f, 0x82, 0xfe, 0xf7, 0x25, 0xaa, 0x08, 0x73, 0xdf, 0xd5, 0xb7,
|
||||
0x7b, 0x63, 0x73, 0xbb, 0x27, 0x25, 0xaa, 0x4a, 0xd4, 0x7e, 0xaa, 0x86, 0x66, 0x93, 0xa1, 0x86,
|
||||
0x5e, 0x93, 0xad, 0x20, 0xe6, 0xf5, 0x8d, 0x8d, 0xd6, 0xb6, 0x8a, 0x86, 0x0f, 0x54, 0xc5, 0xcf,
|
||||
0xa1, 0x2b, 0xd7, 0x98, 0xfb, 0x9e, 0x8e, 0xff, 0xfe, 0xbf, 0x14, 0xec, 0x68, 0xbc, 0xc6, 0xfc,
|
||||
0xeb, 0xa4, 0x50, 0x95, 0xd0, 0xdb, 0x6f, 0xdd, 0x03, 0xaf, 0x31, 0x11, 0x2b, 0x5f, 0x60, 0xa5,
|
||||
0x13, 0xf4, 0x04, 0x2d, 0xf9, 0x07, 0xe0, 0x5e, 0xca, 0xb8, 0x34, 0xcd, 0x19, 0xde, 0xb9, 0xbe,
|
||||
0x09, 0x3b, 0x5e, 0x47, 0xb9, 0x30, 0xce, 0x2f, 0x3b, 0x5f, 0xb0, 0xe0, 0x17, 0x06, 0x5d, 0xb2,
|
||||
0x51, 0x65, 0x63, 0xbc, 0x90, 0x61, 0x75, 0x9c, 0x96, 0xc9, 0x3c, 0xf7, 0xd9, 0xc8, 0x39, 0x74,
|
||||
0xc4, 0x96, 0x8d, 0xbf, 0x0d, 0xbd, 0x99, 0xf1, 0x76, 0x46, 0xce, 0xa1, 0x27, 0x2c, 0xe2, 0x37,
|
||||
0xc0, 0x8d, 0xe5, 0x0c, 0x63, 0x3b, 0x63, 0x06, 0xd0, 0xee, 0x4c, 0xe1, 0x22, 0x5a, 0xdb, 0x11,
|
||||
0xb3, 0x88, 0xec, 0x79, 0xb9, 0x20, 0xbb, 0xe9, 0x9e, 0x45, 0x54, 0xae, 0x99, 0xcc, 0x9b, 0x12,
|
||||
0xd2, 0x9a, 0x22, 0xe7, 0xa1, 0x8c, 0xeb, 0x1a, 0x1a, 0x10, 0xfc, 0xc6, 0x68, 0xb6, 0x0c, 0x27,
|
||||
0x5a, 0xbc, 0x34, 0x15, 0x7d, 0x07, 0x06, 0xc4, 0x97, 0xe7, 0x97, 0x52, 0x59, 0x6e, 0xf6, 0x09,
|
||||
0x3f, 0x93, 0x8a, 0x7f, 0x0a, 0x3d, 0x9d, 0xf9, 0x1e, 0x7e, 0xd6, 0xe1, 0x9e, 0x91, 0x5f, 0xd8,
|
||||
0x6d, 0x4d, 0x07, 0xbb, 0xad, 0x0e, 0x36, 0xc9, 0xba, 0xed, 0x64, 0x6f, 0x83, 0x4b, 0x54, 0xa8,
|
||||
0xf4, 0xed, 0xf7, 0x46, 0x36, 0x84, 0x31, 0xbb, 0x82, 0x73, 0xb8, 0xb6, 0x75, 0x62, 0x73, 0x12,
|
||||
0xdb, 0x3e, 0x69, 0xd3, 0x45, 0xcf, 0x76, 0x8d, 0x74, 0x25, 0xc7, 0x18, 0xc3, 0x02, 0xe7, 0xba,
|
||||
0xde, 0x03, 0xd1, 0xe0, 0xe0, 0x47, 0xb6, 0x89, 0xab, 0xcf, 0x23, 0xe5, 0x08, 0xd3, 0xd5, 0x4a,
|
||||
0x26, 0x73, 0x1b, 0xba, 0x86, 0x54, 0xb7, 0xf9, 0xcc, 0x86, 0xee, 0xcc, 0x67, 0x84, 0x55, 0x66,
|
||||
0x3b, 0xd8, 0x51, 0x19, 0x1f, 0xc1, 0x70, 0x85, 0x32, 0x2f, 0x15, 0xae, 0x30, 0x29, 0x6c, 0x09,
|
||||
0xda, 0x26, 0x7e, 0x13, 0xfa, 0x85, 0xbc, 0x78, 0x4e, 0xdc, 0xb3, 0x9d, 0x2c, 0xe4, 0xc5, 0x7d,
|
||||
0xac, 0xf8, 0xbb, 0xe0, 0x2d, 0x22, 0x8c, 0xe7, 0xda, 0x65, 0xda, 0x39, 0xd0, 0x86, 0xfb, 0x58,
|
||||
0x05, 0x7f, 0x30, 0xe8, 0x4d, 0x51, 0x5d, 0xa2, 0x7a, 0x2d, 0x49, 0x69, 0x4b, 0xb5, 0xf3, 0x0a,
|
||||
0xa9, 0xee, 0xee, 0x97, 0x6a, 0x77, 0x23, 0xd5, 0x37, 0xc0, 0x9d, 0xaa, 0xf0, 0x74, 0xa2, 0x6f,
|
||||
0xe4, 0x08, 0x03, 0x88, 0x8d, 0xe3, 0xb0, 0x88, 0x2e, 0xd1, 0xea, 0xb7, 0x45, 0x3b, 0x4a, 0x33,
|
||||
0xd8, 0xa3, 0x34, 0xbf, 0x33, 0xe8, 0x3d, 0x90, 0x55, 0x5a, 0x16, 0x3b, 0x2c, 0x1c, 0xc1, 0x70,
|
||||
0x9c, 0x65, 0x71, 0x14, 0x9a, 0xaf, 0x4d, 0x46, 0x6d, 0x13, 0xed, 0x78, 0xd8, 0xaa, 0xaf, 0xc9,
|
||||
0xad, 0x6d, 0xa2, 0x29, 0x3e, 0xd1, 0x6a, 0x6a, 0xa4, 0xb1, 0x35, 0xc5, 0x46, 0x44, 0xb5, 0x93,
|
||||
0x8a, 0x30, 0x2e, 0x8b, 0x74, 0x11, 0xa7, 0x57, 0x3a, 0xdb, 0x81, 0x68, 0xf0, 0x4e, 0x12, 0xbd,
|
||||
0x3d, 0x49, 0xfc, 0xd9, 0x81, 0xee, 0xff, 0xa5, 0x92, 0x07, 0xc0, 0x22, 0x7b, 0x09, 0x16, 0x35,
|
||||
0x9a, 0xd9, 0x6f, 0x69, 0xa6, 0x0f, 0xfd, 0x4a, 0xc9, 0xe4, 0x02, 0x73, 0x7f, 0xa0, 0x15, 0xa8,
|
||||
0x86, 0xda, 0xa3, 0x67, 0xcd, 0x88, 0xa5, 0x27, 0x6a, 0xd8, 0xcc, 0x0e, 0xb4, 0x66, 0xe7, 0x13,
|
||||
0xab, 0xab, 0x43, 0x7d, 0x23, 0x7f, 0xbb, 0x74, 0xff, 0x9d, 0x9c, 0xfe, 0xcd, 0xc0, 0x6d, 0x06,
|
||||
0xef, 0x64, 0x7b, 0xf0, 0x4e, 0x36, 0x83, 0x37, 0x39, 0xae, 0x07, 0x6f, 0x72, 0x4c, 0x58, 0x9c,
|
||||
0xd5, 0x83, 0x27, 0xce, 0xa8, 0xa1, 0xf7, 0x54, 0x5a, 0x66, 0xc7, 0x95, 0xe9, 0xbc, 0x27, 0x1a,
|
||||
0x4c, 0x6c, 0xfd, 0x76, 0x89, 0xca, 0x96, 0xda, 0x13, 0x16, 0x11, 0xb7, 0x1f, 0x68, 0x51, 0x32,
|
||||
0xc5, 0x35, 0x80, 0x7f, 0x08, 0xae, 0xa0, 0xe2, 0xe9, 0x0a, 0x6f, 0xf5, 0x45, 0x9b, 0x85, 0xf1,
|
||||
0x52, 0x50, 0xf3, 0x9e, 0xb2, 0x24, 0xaf, 0x5f, 0x57, 0x1f, 0x43, 0x6f, 0xba, 0x8c, 0x16, 0x45,
|
||||
0xfd, 0x77, 0x7a, 0xab, 0x25, 0x6a, 0xd1, 0x0a, 0xb5, 0x4f, 0xd8, 0x2d, 0xc1, 0x13, 0xf0, 0x1a,
|
||||
0xe3, 0xe6, 0x3a, 0xac, 0x7d, 0x1d, 0x0e, 0xdd, 0xf3, 0x24, 0x2a, 0xea, 0xf1, 0xa6, 0x35, 0x25,
|
||||
0xfb, 0xa4, 0x94, 0x49, 0x11, 0x15, 0x55, 0x3d, 0xde, 0x35, 0x0e, 0xee, 0xda, 0xeb, 0x53, 0xb8,
|
||||
0xf3, 0x2c, 0x43, 0x65, 0xa5, 0xc2, 0x00, 0x7d, 0x48, 0x7a, 0x85, 0x46, 0xe5, 0x1d, 0x61, 0x40,
|
||||
0xf0, 0x1d, 0x78, 0xe3, 0x18, 0x55, 0x21, 0xca, 0x78, 0xf7, 0xdf, 0xc0, 0xa1, 0xfb, 0xcd, 0xf4,
|
||||
0xf1, 0xa3, 0xfa, 0x06, 0xb4, 0xde, 0xc8, 0x82, 0xf3, 0x92, 0x2c, 0xdc, 0x97, 0x99, 0x3c, 0x9d,
|
||||
0x68, 0x9e, 0x3b, 0xc2, 0xa2, 0xe0, 0x27, 0x06, 0x5d, 0xd2, 0x9f, 0x56, 0xe8, 0xee, 0xab, 0xb4,
|
||||
0xeb, 0x4c, 0xa5, 0x97, 0xd1, 0x1c, 0x55, 0x9d, 0x5c, 0x8d, 0x75, 0xd1, 0xc3, 0x25, 0x36, 0x0f,
|
||||
0x50, 0x8b, 0x88, 0x6b, 0xf4, 0xf8, 0xaa, 0x67, 0xa9, 0xc5, 0x35, 0x32, 0x0b, 0xe3, 0xe4, 0xef,
|
||||
0x01, 0x4c, 0xcb, 0x0c, 0xd5, 0x78, 0xbe, 0x8a, 0xcc, 0x58, 0x0f, 0x44, 0xcb, 0x12, 0x7c, 0x65,
|
||||
0x9e, 0x73, 0x3b, 0x02, 0xc0, 0xf6, 0x3f, 0xfd, 0x5e, 0xbe, 0x79, 0x10, 0x6f, 0x7f, 0xf7, 0x5a,
|
||||
0xd9, 0x8e, 0x60, 0x68, 0xdf, 0xbe, 0xfa, 0x25, 0x69, 0x05, 0xad, 0x65, 0xa2, 0x9c, 0xcf, 0xca,
|
||||
0x59, 0x1c, 0x85, 0x3a, 0xe7, 0x81, 0xb0, 0x68, 0xd6, 0xd3, 0x4f, 0xfc, 0xbb, 0xff, 0x04, 0x00,
|
||||
0x00, 0xff, 0xff, 0xe3, 0xb7, 0x65, 0x8a, 0xf4, 0x0b, 0x00, 0x00,
|
||||
0xe5, 0x09, 0x55, 0x1b, 0x67, 0x72, 0xb1, 0xea, 0xd8, 0x66, 0x6d, 0xdf, 0x9d, 0xf9, 0x30, 0x48,
|
||||
0x48, 0x3c, 0xf1, 0x88, 0x78, 0xe7, 0x15, 0xf1, 0x41, 0xf8, 0x0a, 0xbc, 0xa2, 0xd9, 0x5d, 0x3b,
|
||||
0x4e, 0x2f, 0x54, 0x7d, 0x81, 0xb7, 0xfd, 0xcd, 0xac, 0x67, 0x77, 0x66, 0x7e, 0xf3, 0xf3, 0xc2,
|
||||
0xf5, 0x38, 0x2d, 0x51, 0xa5, 0x32, 0x39, 0xc8, 0x55, 0x56, 0x66, 0xdc, 0x6b, 0x70, 0xf8, 0x57,
|
||||
0x0f, 0x06, 0xb3, 0xac, 0x52, 0x11, 0xf2, 0xeb, 0xd0, 0x3b, 0x9e, 0x06, 0x6c, 0xcc, 0xf6, 0x1d,
|
||||
0xd1, 0x3b, 0x9e, 0x72, 0x0e, 0xfd, 0x47, 0x72, 0x8d, 0x41, 0x6f, 0xcc, 0xf6, 0x7d, 0xa1, 0xd7,
|
||||
0x64, 0x7b, 0x5a, 0xe7, 0x18, 0x38, 0xc6, 0x46, 0x6b, 0x7e, 0x0b, 0xbc, 0xd3, 0x82, 0xa2, 0xad,
|
||||
0x31, 0xe8, 0x6b, 0x7b, 0x8b, 0xc9, 0x77, 0x22, 0x8b, 0xe2, 0x22, 0x53, 0x8b, 0xc0, 0x35, 0xbe,
|
||||
0x06, 0xf3, 0x37, 0xc1, 0x39, 0x15, 0x0f, 0x82, 0x81, 0x36, 0xd3, 0x92, 0x07, 0x30, 0x9c, 0xe2,
|
||||
0x52, 0x56, 0x49, 0x19, 0x0c, 0xc7, 0x6c, 0xdf, 0x13, 0x0d, 0xa4, 0x38, 0x4f, 0x31, 0xc1, 0x33,
|
||||
0x25, 0x97, 0x81, 0x67, 0xe2, 0x34, 0x98, 0x1f, 0x00, 0x3f, 0x4e, 0x0b, 0x8c, 0x2a, 0x85, 0xb3,
|
||||
0x17, 0x71, 0xfe, 0x0c, 0x55, 0xbc, 0xac, 0x03, 0x5f, 0x07, 0xd8, 0xe1, 0xa1, 0x53, 0x1e, 0x62,
|
||||
0x29, 0xe9, 0x6c, 0xd0, 0xa1, 0x1a, 0xc8, 0x43, 0xd8, 0x9b, 0xad, 0xa4, 0xc2, 0xc5, 0x0c, 0x23,
|
||||
0x85, 0x65, 0x30, 0xd2, 0xee, 0x2d, 0x1b, 0xed, 0x79, 0xac, 0xce, 0x64, 0x1a, 0xff, 0x20, 0xcb,
|
||||
0x38, 0x4b, 0x83, 0x3d, 0xb3, 0xa7, 0x6b, 0xa3, 0x2a, 0x89, 0x2c, 0xc1, 0xe0, 0x9a, 0xa9, 0x12,
|
||||
0xad, 0xc3, 0xdf, 0x18, 0xf8, 0x53, 0x59, 0xac, 0xe6, 0x99, 0x54, 0x8b, 0xd7, 0xaa, 0xf5, 0x6d,
|
||||
0x70, 0x23, 0x4c, 0x92, 0x22, 0x70, 0xc6, 0xce, 0xfe, 0xe8, 0xce, 0xcd, 0x83, 0xb6, 0x89, 0x6d,
|
||||
0x9c, 0x23, 0x4c, 0x12, 0x61, 0x76, 0xf1, 0xcf, 0xc0, 0x2f, 0x71, 0x9d, 0x27, 0xb2, 0xc4, 0x22,
|
||||
0xe8, 0xeb, 0x4f, 0xf8, 0xe6, 0x93, 0xa7, 0xd6, 0x25, 0x36, 0x9b, 0xae, 0xa4, 0xe2, 0x5e, 0x4d,
|
||||
0x25, 0xfc, 0xa5, 0x07, 0xd7, 0xb6, 0x8e, 0xe3, 0x7b, 0xc0, 0x2e, 0xf5, 0xcd, 0x5d, 0xc1, 0x2e,
|
||||
0x09, 0xd5, 0xfa, 0xd6, 0xae, 0x60, 0x35, 0xa1, 0x0b, 0xcd, 0x0d, 0x57, 0xb0, 0x0b, 0x42, 0x2b,
|
||||
0xcd, 0x08, 0x57, 0xb0, 0x15, 0xff, 0x08, 0x86, 0xdf, 0x57, 0xa8, 0x62, 0x2c, 0x02, 0x57, 0xdf,
|
||||
0xee, 0x8d, 0xcd, 0xed, 0x9e, 0x54, 0xa8, 0x6a, 0xd1, 0xf8, 0xa9, 0x1a, 0x9a, 0x4d, 0x86, 0x1a,
|
||||
0x7a, 0x4d, 0xb6, 0x92, 0x98, 0x37, 0x34, 0x36, 0x5a, 0xdb, 0x2a, 0x1a, 0x3e, 0x50, 0x15, 0x3f,
|
||||
0x87, 0xbe, 0xbc, 0xc4, 0x22, 0xf0, 0x75, 0xfc, 0xf7, 0xff, 0xa5, 0x60, 0x07, 0x93, 0x4b, 0x2c,
|
||||
0xbe, 0x4e, 0x4b, 0x55, 0x0b, 0xbd, 0xfd, 0xd6, 0x3d, 0xf0, 0x5b, 0x13, 0xb1, 0xf2, 0x05, 0xd6,
|
||||
0x3a, 0x41, 0x5f, 0xd0, 0x92, 0x7f, 0x00, 0xee, 0xb9, 0x4c, 0x2a, 0xd3, 0x9c, 0xd1, 0x9d, 0xeb,
|
||||
0x9b, 0xb0, 0x93, 0xcb, 0xb8, 0x10, 0xc6, 0xf9, 0x65, 0xef, 0x0b, 0x16, 0xfe, 0xca, 0xa0, 0x4f,
|
||||
0x36, 0xaa, 0x6c, 0x82, 0x67, 0x32, 0xaa, 0x0f, 0xb3, 0x2a, 0x5d, 0x14, 0x01, 0x1b, 0x3b, 0xfb,
|
||||
0x8e, 0xd8, 0xb2, 0xf1, 0xb7, 0x61, 0x30, 0x37, 0xde, 0xde, 0xd8, 0xd9, 0xf7, 0x85, 0x45, 0xfc,
|
||||
0x06, 0xb8, 0x89, 0x9c, 0x63, 0x62, 0x67, 0xcc, 0x00, 0xda, 0x9d, 0x2b, 0x5c, 0xc6, 0x97, 0x76,
|
||||
0xc4, 0x2c, 0x22, 0x7b, 0x51, 0x2d, 0xc9, 0x6e, 0xba, 0x67, 0x11, 0x95, 0x6b, 0x2e, 0x8b, 0xb6,
|
||||
0x84, 0xb4, 0xa6, 0xc8, 0x45, 0x24, 0x93, 0xa6, 0x86, 0x06, 0x84, 0xbf, 0x33, 0x9a, 0x2d, 0xc3,
|
||||
0x89, 0x0e, 0x2f, 0x4d, 0x45, 0xdf, 0x01, 0x8f, 0xf8, 0xf2, 0xfc, 0x5c, 0x2a, 0xcb, 0xcd, 0x21,
|
||||
0xe1, 0x67, 0x52, 0xf1, 0x4f, 0x61, 0xa0, 0x33, 0xdf, 0xc1, 0xcf, 0x26, 0xdc, 0x33, 0xf2, 0x0b,
|
||||
0xbb, 0xad, 0xed, 0x60, 0xbf, 0xd3, 0xc1, 0x36, 0x59, 0xb7, 0x9b, 0xec, 0x6d, 0x70, 0x89, 0x0a,
|
||||
0xb5, 0xbe, 0xfd, 0xce, 0xc8, 0x86, 0x30, 0x66, 0x57, 0x78, 0x0a, 0xd7, 0xb6, 0x4e, 0x6c, 0x4f,
|
||||
0x62, 0xdb, 0x27, 0x6d, 0xba, 0xe8, 0xdb, 0xae, 0x91, 0xae, 0x14, 0x98, 0x60, 0x54, 0xe2, 0x42,
|
||||
0xd7, 0xdb, 0x13, 0x2d, 0x0e, 0x7f, 0x62, 0x9b, 0xb8, 0xfa, 0x3c, 0x52, 0x8e, 0x28, 0x5b, 0xaf,
|
||||
0x65, 0xba, 0xb0, 0xa1, 0x1b, 0x48, 0x75, 0x5b, 0xcc, 0x6d, 0xe8, 0xde, 0x62, 0x4e, 0x58, 0xe5,
|
||||
0xb6, 0x83, 0x3d, 0x95, 0xf3, 0x31, 0x8c, 0xd6, 0x28, 0x8b, 0x4a, 0xe1, 0x1a, 0xd3, 0xd2, 0x96,
|
||||
0xa0, 0x6b, 0xe2, 0x37, 0x61, 0x58, 0xca, 0xb3, 0xe7, 0xc4, 0x3d, 0xdb, 0xc9, 0x52, 0x9e, 0xdd,
|
||||
0xc7, 0x9a, 0xbf, 0x0b, 0xfe, 0x32, 0xc6, 0x64, 0xa1, 0x5d, 0xa6, 0x9d, 0x9e, 0x36, 0xdc, 0xc7,
|
||||
0x3a, 0xfc, 0x83, 0xc1, 0x60, 0x86, 0xea, 0x1c, 0xd5, 0x6b, 0x49, 0x4a, 0x57, 0xaa, 0x9d, 0x57,
|
||||
0x48, 0x75, 0x7f, 0xb7, 0x54, 0xbb, 0x1b, 0xa9, 0xbe, 0x01, 0xee, 0x4c, 0x45, 0xc7, 0x53, 0x7d,
|
||||
0x23, 0x47, 0x18, 0x40, 0x6c, 0x9c, 0x44, 0x65, 0x7c, 0x8e, 0x56, 0xbf, 0x2d, 0xba, 0xa2, 0x34,
|
||||
0xde, 0x0e, 0xa5, 0xf9, 0x91, 0xc1, 0xe0, 0x81, 0xac, 0xb3, 0xaa, 0xbc, 0xc2, 0xc2, 0x31, 0x8c,
|
||||
0x26, 0x79, 0x9e, 0xc4, 0x91, 0xf9, 0xda, 0x64, 0xd4, 0x35, 0xd1, 0x8e, 0x87, 0x9d, 0xfa, 0x9a,
|
||||
0xdc, 0xba, 0x26, 0x9a, 0xe2, 0x23, 0xad, 0xa6, 0x46, 0x1a, 0x3b, 0x53, 0x6c, 0x44, 0x54, 0x3b,
|
||||
0xa9, 0x08, 0x93, 0xaa, 0xcc, 0x96, 0x49, 0x76, 0xa1, 0xb3, 0xf5, 0x44, 0x8b, 0xc3, 0x3f, 0x7b,
|
||||
0xd0, 0xff, 0xbf, 0x14, 0x70, 0x0f, 0x58, 0x6c, 0x9b, 0xcd, 0xe2, 0x56, 0x0f, 0x87, 0x1d, 0x3d,
|
||||
0x0c, 0x60, 0x58, 0x2b, 0x99, 0x9e, 0x61, 0x11, 0x78, 0x5a, 0x5d, 0x1a, 0xa8, 0x3d, 0x7a, 0x8e,
|
||||
0x8c, 0x10, 0xfa, 0xa2, 0x81, 0xed, 0x5c, 0x40, 0x67, 0x2e, 0x3e, 0xb1, 0x9a, 0x39, 0xd2, 0x37,
|
||||
0x0a, 0xb6, 0xcb, 0xf2, 0xdf, 0x49, 0xe5, 0xdf, 0x0c, 0xdc, 0x76, 0xa8, 0x8e, 0xb6, 0x87, 0xea,
|
||||
0x68, 0x33, 0x54, 0xd3, 0xc3, 0x66, 0xa8, 0xa6, 0x87, 0x84, 0xc5, 0x49, 0x33, 0x54, 0xe2, 0x84,
|
||||
0x9a, 0x75, 0x4f, 0x65, 0x55, 0x7e, 0x58, 0x9b, 0xae, 0xfa, 0xa2, 0xc5, 0xc4, 0xc4, 0x6f, 0x57,
|
||||
0xa8, 0x6c, 0xa9, 0x7d, 0x61, 0x11, 0xf1, 0xf6, 0x81, 0x16, 0x1c, 0x53, 0x5c, 0x03, 0xf8, 0x87,
|
||||
0xe0, 0x0a, 0x2a, 0x9e, 0xae, 0xf0, 0x56, 0x5f, 0xb4, 0x59, 0x18, 0x2f, 0x05, 0x35, 0x6f, 0x25,
|
||||
0x4b, 0xe0, 0xe6, 0xe5, 0xf4, 0x31, 0x0c, 0x66, 0xab, 0x78, 0x59, 0x36, 0x7f, 0x9e, 0xb7, 0x3a,
|
||||
0x82, 0x15, 0xaf, 0x51, 0xfb, 0x84, 0xdd, 0x12, 0x3e, 0x01, 0xbf, 0x35, 0x6e, 0xae, 0xc3, 0xba,
|
||||
0xd7, 0xe1, 0xd0, 0x3f, 0x4d, 0xe3, 0xb2, 0x19, 0x5d, 0x5a, 0x53, 0xb2, 0x4f, 0x2a, 0x99, 0x96,
|
||||
0x71, 0x59, 0x37, 0xa3, 0xdb, 0xe0, 0xf0, 0xae, 0xbd, 0x3e, 0x85, 0x3b, 0xcd, 0x73, 0x54, 0x56,
|
||||
0x06, 0x0c, 0xd0, 0x87, 0x64, 0x17, 0x68, 0x14, 0xdc, 0x11, 0x06, 0x84, 0xdf, 0x81, 0x3f, 0x49,
|
||||
0x50, 0x95, 0xa2, 0x4a, 0xae, 0xea, 0x3e, 0x87, 0xfe, 0x37, 0xb3, 0xc7, 0x8f, 0x9a, 0x1b, 0xd0,
|
||||
0x7a, 0x33, 0xf2, 0xce, 0x4b, 0x23, 0x7f, 0x5f, 0xe6, 0xf2, 0x78, 0xaa, 0x79, 0xee, 0x08, 0x8b,
|
||||
0xc2, 0x9f, 0x19, 0xf4, 0x49, 0x5b, 0x3a, 0xa1, 0xfb, 0xaf, 0xd2, 0xa5, 0x13, 0x95, 0x9d, 0xc7,
|
||||
0x0b, 0x54, 0x4d, 0x72, 0x0d, 0xd6, 0x45, 0x8f, 0x56, 0xd8, 0x3e, 0x2e, 0x2d, 0x22, 0xae, 0xd1,
|
||||
0xc3, 0xaa, 0x99, 0xa5, 0x0e, 0xd7, 0xc8, 0x2c, 0x8c, 0x93, 0xbf, 0x07, 0x30, 0xab, 0x72, 0x54,
|
||||
0x93, 0xc5, 0x3a, 0x4e, 0x75, 0xd3, 0x3d, 0xd1, 0xb1, 0x84, 0x5f, 0x99, 0xa7, 0xda, 0x15, 0x85,
|
||||
0x62, 0xbb, 0x9f, 0x75, 0x2f, 0xdf, 0x3c, 0x4c, 0xb6, 0xbf, 0x7b, 0xad, 0x6c, 0xc7, 0x30, 0xb2,
|
||||
0xef, 0x5a, 0xfd, 0x4a, 0xb4, 0x62, 0xd5, 0x31, 0x51, 0xce, 0x27, 0xd5, 0x3c, 0x89, 0x23, 0x9d,
|
||||
0xb3, 0x27, 0x2c, 0x9a, 0x0f, 0xf4, 0xf3, 0xfd, 0xee, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaa,
|
||||
0x43, 0x90, 0xf1, 0xd0, 0x0b, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -88,7 +88,6 @@ message Layout {
|
|||
string Measurement = 3; // Measurement is the descriptive name of the time series data.
|
||||
repeated Cell Cells = 4; // Cells are the individual visualization elements.
|
||||
bool Autoflow = 5; // Autoflow indicates whether the frontend should layout the cells automatically.
|
||||
string Organization = 6; // Organization is the organization ID that resource belongs to
|
||||
}
|
||||
|
||||
message Cell {
|
||||
|
|
|
@ -2,7 +2,6 @@ package bolt
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/influxdata/chronograf"
|
||||
|
@ -22,27 +21,6 @@ type LayoutsStore struct {
|
|||
}
|
||||
|
||||
func (s *LayoutsStore) Migrate(ctx context.Context) error {
|
||||
layouts, err := s.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaultOrg, err := s.client.OrganizationsStore.DefaultOrganization(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaultOrgID := fmt.Sprintf("%d", defaultOrg.ID)
|
||||
|
||||
for _, layout := range layouts {
|
||||
if layout.Organization == "" {
|
||||
layout.Organization = defaultOrgID
|
||||
if err := s.Update(ctx, layout); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -168,17 +168,6 @@ func (s *OrganizationsStore) Delete(ctx context.Context, o *chronograf.Organizat
|
|||
}
|
||||
}
|
||||
|
||||
layoutsStore := organizations.NewLayoutsStore(s.client.LayoutsStore, org)
|
||||
layouts, err := layoutsStore.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, layout := range layouts {
|
||||
if err := layoutsStore.Delete(ctx, layout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dashboardsStore := organizations.NewDashboardsStore(s.client.DashboardsStore, org)
|
||||
dashboards, err := dashboardsStore.All(ctx)
|
||||
if err != nil {
|
||||
|
|
|
@ -526,12 +526,11 @@ type Cell struct {
|
|||
|
||||
// Layout is a collection of Cells for visualization
|
||||
type Layout struct {
|
||||
ID string `json:"id"`
|
||||
Application string `json:"app"`
|
||||
Measurement string `json:"measurement"`
|
||||
Autoflow bool `json:"autoflow"`
|
||||
Cells []Cell `json:"cells"`
|
||||
Organization string `json:"organization"` // Organization is the organization ID that resource belongs to
|
||||
ID string `json:"id"`
|
||||
Application string `json:"app"`
|
||||
Measurement string `json:"measurement"`
|
||||
Autoflow bool `json:"autoflow"`
|
||||
Cells []Cell `json:"cells"`
|
||||
}
|
||||
|
||||
// LayoutsStore stores dashboards and associated Cells
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
package integrations
|
||||
|
||||
// This was intentionally added under the integrations package and not the integrations test package
|
||||
// so that changes in other parts of the code base that may have an effect on these test will not
|
||||
// compile until they are fixed.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/bolt"
|
||||
"github.com/influxdata/chronograf/oauth2"
|
||||
"github.com/influxdata/chronograf/server"
|
||||
)
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
type fields struct {
|
||||
Organizations []chronograf.Organization
|
||||
Users []chronograf.User
|
||||
Sources []chronograf.Source
|
||||
Servers []chronograf.Server
|
||||
Layouts []chronograf.Layout
|
||||
Dashboards []chronograf.Dashboard
|
||||
}
|
||||
type args struct {
|
||||
server *server.Server
|
||||
method string
|
||||
path string
|
||||
payload interface{} // Expects this to be a json serializable struct
|
||||
principal oauth2.Principal
|
||||
}
|
||||
type wants struct {
|
||||
statusCode int
|
||||
contentType string
|
||||
body string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
subName string
|
||||
fields fields
|
||||
args args
|
||||
wants wants
|
||||
}{
|
||||
{
|
||||
name: "GET /users",
|
||||
subName: "User Not Found in the Default Organization",
|
||||
fields: fields{
|
||||
Users: []chronograf.User{},
|
||||
},
|
||||
args: args{
|
||||
server: &server.Server{
|
||||
GithubClientID: "not empty",
|
||||
GithubClientSecret: "not empty",
|
||||
},
|
||||
method: "GET",
|
||||
path: "/chronograf/v1/users",
|
||||
principal: oauth2.Principal{
|
||||
Organization: "0",
|
||||
Subject: "billibob",
|
||||
Issuer: "github",
|
||||
},
|
||||
},
|
||||
wants: wants{
|
||||
statusCode: 401,
|
||||
body: `{"code":401,"message":"User is not authorized"}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GET /users",
|
||||
subName: "Single User in the Default Organization as SuperAdmin",
|
||||
fields: fields{
|
||||
Users: []chronograf.User{
|
||||
{
|
||||
ID: 1, // This is artificial, but should be reflective of the users actual ID
|
||||
Name: "billibob",
|
||||
Provider: "github",
|
||||
Scheme: "oauth2",
|
||||
SuperAdmin: true,
|
||||
Roles: []chronograf.Role{
|
||||
{
|
||||
Name: "admin",
|
||||
Organization: "0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
server: &server.Server{
|
||||
GithubClientID: "not empty",
|
||||
GithubClientSecret: "not empty",
|
||||
},
|
||||
method: "GET",
|
||||
path: "/chronograf/v1/users",
|
||||
principal: oauth2.Principal{
|
||||
Organization: "0",
|
||||
Subject: "billibob",
|
||||
Issuer: "github",
|
||||
},
|
||||
},
|
||||
wants: wants{
|
||||
statusCode: 200,
|
||||
body: `
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/users"
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"links": {
|
||||
"self": "/chronograf/v1/users/1"
|
||||
},
|
||||
"id": "1",
|
||||
"name": "billibob",
|
||||
"provider": "github",
|
||||
"scheme": "oauth2",
|
||||
"superAdmin": true,
|
||||
"roles": [
|
||||
{
|
||||
"name": "admin",
|
||||
"organization": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
testName := fmt.Sprintf("%s: %s", tt.name, tt.subName)
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
// Create Test Server
|
||||
host, port := hostAndPort()
|
||||
tt.args.server.Host = host
|
||||
tt.args.server.Port = port
|
||||
|
||||
// This is so that we can use staticly generate jwts
|
||||
tt.args.server.TokenSecret = "secret"
|
||||
|
||||
boltFile := newBoltFile()
|
||||
tt.args.server.BoltPath = boltFile
|
||||
|
||||
// Prepopulate BoltDB Database for Server
|
||||
boltdb := bolt.NewClient()
|
||||
boltdb.Path = boltFile
|
||||
_ = boltdb.Open(ctx)
|
||||
|
||||
// Populate Organizations
|
||||
for i, organization := range tt.fields.Organizations {
|
||||
o, err := boltdb.OrganizationsStore.Add(ctx, &organization)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add organization: %v", err)
|
||||
return
|
||||
}
|
||||
tt.fields.Organizations[i] = *o
|
||||
}
|
||||
|
||||
// Populate Users
|
||||
for i, user := range tt.fields.Users {
|
||||
u, err := boltdb.UsersStore.Add(ctx, &user)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add user: %v", err)
|
||||
return
|
||||
}
|
||||
tt.fields.Users[i] = *u
|
||||
}
|
||||
|
||||
// Populate Sources
|
||||
for i, source := range tt.fields.Sources {
|
||||
s, err := boltdb.SourcesStore.Add(ctx, source)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add source: %v", err)
|
||||
return
|
||||
}
|
||||
tt.fields.Sources[i] = s
|
||||
}
|
||||
|
||||
// Populate Servers
|
||||
for i, server := range tt.fields.Servers {
|
||||
s, err := boltdb.ServersStore.Add(ctx, server)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add server: %v", err)
|
||||
return
|
||||
}
|
||||
tt.fields.Servers[i] = s
|
||||
}
|
||||
|
||||
// Populate Layouts
|
||||
for i, layout := range tt.fields.Layouts {
|
||||
l, err := boltdb.LayoutsStore.Add(ctx, layout)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add layout: %v", err)
|
||||
return
|
||||
}
|
||||
tt.fields.Layouts[i] = l
|
||||
}
|
||||
|
||||
// Populate Dashboards
|
||||
for i, dashboard := range tt.fields.Dashboards {
|
||||
d, err := boltdb.DashboardsStore.Add(ctx, dashboard)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add dashboard: %v", err)
|
||||
return
|
||||
}
|
||||
tt.fields.Dashboards[i] = d
|
||||
}
|
||||
|
||||
_ = boltdb.Close()
|
||||
|
||||
go tt.args.server.Serve(ctx)
|
||||
serverURL := fmt.Sprintf("http://%v:%v%v", host, port, tt.args.path)
|
||||
|
||||
// Wait for the server to come online
|
||||
timeout := time.Now().Add(100 * time.Millisecond)
|
||||
for {
|
||||
_, err := http.Get(serverURL + "/swagger.json")
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if time.Now().After(timeout) {
|
||||
t.Fatalf("failed to start server")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Expiry time on the principal
|
||||
tt.args.principal.IssuedAt = time.Now()
|
||||
tt.args.principal.ExpiresAt = time.Now().Add(10 * time.Second)
|
||||
|
||||
// Construct HTTP Request
|
||||
buf, _ := json.Marshal(tt.args.payload)
|
||||
reqBody := ioutil.NopCloser(bytes.NewReader(buf))
|
||||
req, _ := http.NewRequest(tt.args.method, serverURL, reqBody)
|
||||
token, _ := oauth2.NewJWT(tt.args.server.TokenSecret).Create(ctx, tt.args.principal)
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: "session",
|
||||
Value: string(token),
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
})
|
||||
|
||||
// Make actual http request
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to make httprequest: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
content := resp.Header.Get("Content-Type")
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if resp.StatusCode != tt.wants.statusCode {
|
||||
t.Errorf(
|
||||
"%s %s Status Code = %v, want %v",
|
||||
tt.args.method,
|
||||
tt.args.path,
|
||||
resp.StatusCode,
|
||||
tt.wants.statusCode,
|
||||
)
|
||||
}
|
||||
|
||||
if tt.wants.contentType != "" && content != tt.wants.contentType {
|
||||
t.Errorf(
|
||||
"%s %s Content Type = %v, want %v",
|
||||
tt.args.method,
|
||||
tt.args.path,
|
||||
content,
|
||||
tt.wants.contentType,
|
||||
)
|
||||
}
|
||||
|
||||
if eq, err := jsonEqual(tt.wants.body, string(body)); err != nil || !eq {
|
||||
t.Errorf(
|
||||
"%s %s Body = %v, want %v",
|
||||
tt.args.method,
|
||||
tt.args.path,
|
||||
string(body),
|
||||
tt.wants.body,
|
||||
)
|
||||
}
|
||||
|
||||
tt.args.server.Listener.Close()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func hostAndPort() (string, int) {
|
||||
s := httptest.NewServer(nil)
|
||||
defer s.Close()
|
||||
|
||||
u, err := url.Parse(s.URL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
xs := strings.Split(u.Host, ":")
|
||||
host := xs[0]
|
||||
portStr := xs[1]
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return host, port
|
||||
|
||||
}
|
||||
|
||||
func newBoltFile() string {
|
||||
f, err := ioutil.TempFile("", "chronograf-bolt-")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
func jsonEqual(s1, s2 string) (eq bool, err error) {
|
||||
var o1, o2 interface{}
|
||||
|
||||
if err = json.Unmarshal([]byte(s1), &o1); err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal([]byte(s2), &o2); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return cmp.Equal(o1, o2), nil
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
package organizations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/influxdata/chronograf"
|
||||
)
|
||||
|
||||
// ensure that LayoutsStore implements chronograf.LayoutStore
|
||||
var _ chronograf.LayoutsStore = &LayoutsStore{}
|
||||
|
||||
// LayoutsStore facade on a LayoutStore that filters layouts
|
||||
// by organization.
|
||||
type LayoutsStore struct {
|
||||
store chronograf.LayoutsStore
|
||||
organization string
|
||||
}
|
||||
|
||||
// NewLayoutsStore creates a new LayoutsStore from an existing
|
||||
// chronograf.LayoutStore and an organization string
|
||||
func NewLayoutsStore(s chronograf.LayoutsStore, org string) *LayoutsStore {
|
||||
return &LayoutsStore{
|
||||
store: s,
|
||||
organization: org,
|
||||
}
|
||||
}
|
||||
|
||||
// All retrieves all layouts from the underlying LayoutStore and filters them
|
||||
// by organization.
|
||||
func (s *LayoutsStore) All(ctx context.Context) ([]chronograf.Layout, error) {
|
||||
err := validOrganization(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds, err := s.store.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This filters layouts without allocating
|
||||
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
|
||||
layouts := ds[:0]
|
||||
for _, d := range ds {
|
||||
if d.Organization == s.organization {
|
||||
layouts = append(layouts, d)
|
||||
}
|
||||
}
|
||||
|
||||
return layouts, nil
|
||||
}
|
||||
|
||||
// Add creates a new Layout in the LayoutsStore with layout.Organization set to be the
|
||||
// organization from the layout store.
|
||||
func (s *LayoutsStore) Add(ctx context.Context, d chronograf.Layout) (chronograf.Layout, error) {
|
||||
err := validOrganization(ctx)
|
||||
if err != nil {
|
||||
return chronograf.Layout{}, err
|
||||
}
|
||||
|
||||
d.Organization = s.organization
|
||||
return s.store.Add(ctx, d)
|
||||
}
|
||||
|
||||
// Delete the layout from LayoutsStore
|
||||
func (s *LayoutsStore) Delete(ctx context.Context, d chronograf.Layout) error {
|
||||
err := validOrganization(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d, err = s.store.Get(ctx, d.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.store.Delete(ctx, d)
|
||||
}
|
||||
|
||||
// Get returns a Layout if the id exists and belongs to the organization that is set.
|
||||
func (s *LayoutsStore) Get(ctx context.Context, id string) (chronograf.Layout, error) {
|
||||
err := validOrganization(ctx)
|
||||
if err != nil {
|
||||
return chronograf.Layout{}, err
|
||||
}
|
||||
|
||||
d, err := s.store.Get(ctx, id)
|
||||
if err != nil {
|
||||
return chronograf.Layout{}, err
|
||||
}
|
||||
|
||||
if d.Organization != s.organization {
|
||||
return chronograf.Layout{}, chronograf.ErrLayoutNotFound
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Update the layout in LayoutsStore.
|
||||
func (s *LayoutsStore) Update(ctx context.Context, d chronograf.Layout) error {
|
||||
err := validOrganization(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.store.Get(ctx, d.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.store.Update(ctx, d)
|
||||
}
|
|
@ -1,339 +0,0 @@
|
|||
package organizations_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/influxdata/chronograf"
|
||||
"github.com/influxdata/chronograf/mocks"
|
||||
"github.com/influxdata/chronograf/organizations"
|
||||
)
|
||||
|
||||
// IgnoreFields is used because ID cannot be predicted reliably
|
||||
// EquateEmpty is used because we want nil slices, arrays, and maps to be equal to the empty map
|
||||
var layoutCmpOptions = cmp.Options{
|
||||
cmpopts.EquateEmpty(),
|
||||
cmpopts.IgnoreFields(chronograf.Layout{}, "ID"),
|
||||
}
|
||||
|
||||
func TestLayouts_All(t *testing.T) {
|
||||
type fields struct {
|
||||
LayoutsStore chronograf.LayoutsStore
|
||||
}
|
||||
type args struct {
|
||||
organization string
|
||||
ctx context.Context
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
fields fields
|
||||
want []chronograf.Layout
|
||||
wantRaw []chronograf.Layout
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "No Layouts",
|
||||
fields: fields{
|
||||
LayoutsStore: &mocks.LayoutsStore{
|
||||
AllF: func(ctx context.Context) ([]chronograf.Layout, error) {
|
||||
return nil, fmt.Errorf("No Layouts")
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "All Layouts",
|
||||
fields: fields{
|
||||
LayoutsStore: &mocks.LayoutsStore{
|
||||
AllF: func(ctx context.Context) ([]chronograf.Layout, error) {
|
||||
return []chronograf.Layout{
|
||||
{
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
{
|
||||
Application: "doody",
|
||||
Organization: "1338",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
organization: "1337",
|
||||
ctx: context.Background(),
|
||||
},
|
||||
want: []chronograf.Layout{
|
||||
{
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s := organizations.NewLayoutsStore(tt.fields.LayoutsStore, tt.args.organization)
|
||||
tt.args.ctx = context.WithValue(tt.args.ctx, organizations.ContextKey, tt.args.organization)
|
||||
gots, err := s.All(tt.args.ctx)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("%q. LayoutsStore.All() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
for i, got := range gots {
|
||||
if diff := cmp.Diff(got, tt.want[i], layoutCmpOptions...); diff != "" {
|
||||
t.Errorf("%q. LayoutsStore.All():\n-got/+want\ndiff %s", tt.name, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayouts_Add(t *testing.T) {
|
||||
type fields struct {
|
||||
LayoutsStore chronograf.LayoutsStore
|
||||
}
|
||||
type args struct {
|
||||
organization string
|
||||
ctx context.Context
|
||||
layout chronograf.Layout
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
fields fields
|
||||
want chronograf.Layout
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Add Layout",
|
||||
fields: fields{
|
||||
LayoutsStore: &mocks.LayoutsStore{
|
||||
AddF: func(ctx context.Context, s chronograf.Layout) (chronograf.Layout, error) {
|
||||
return s, nil
|
||||
},
|
||||
GetF: func(ctx context.Context, id string) (chronograf.Layout, error) {
|
||||
return chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
organization: "1337",
|
||||
ctx: context.Background(),
|
||||
layout: chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
},
|
||||
},
|
||||
want: chronograf.Layout{
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s := organizations.NewLayoutsStore(tt.fields.LayoutsStore, tt.args.organization)
|
||||
tt.args.ctx = context.WithValue(tt.args.ctx, organizations.ContextKey, tt.args.organization)
|
||||
d, err := s.Add(tt.args.ctx, tt.args.layout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("%q. LayoutsStore.Add() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
got, err := s.Get(tt.args.ctx, d.ID)
|
||||
if diff := cmp.Diff(got, tt.want, layoutCmpOptions...); diff != "" {
|
||||
t.Errorf("%q. LayoutsStore.Add():\n-got/+want\ndiff %s", tt.name, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayouts_Delete(t *testing.T) {
|
||||
type fields struct {
|
||||
LayoutsStore chronograf.LayoutsStore
|
||||
}
|
||||
type args struct {
|
||||
organization string
|
||||
ctx context.Context
|
||||
layout chronograf.Layout
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want []chronograf.Layout
|
||||
addFirst bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Delete layout",
|
||||
fields: fields{
|
||||
LayoutsStore: &mocks.LayoutsStore{
|
||||
DeleteF: func(ctx context.Context, s chronograf.Layout) error {
|
||||
return nil
|
||||
},
|
||||
GetF: func(ctx context.Context, id string) (chronograf.Layout, error) {
|
||||
return chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
organization: "1337",
|
||||
ctx: context.Background(),
|
||||
layout: chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
},
|
||||
addFirst: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s := organizations.NewLayoutsStore(tt.fields.LayoutsStore, tt.args.organization)
|
||||
tt.args.ctx = context.WithValue(tt.args.ctx, organizations.ContextKey, tt.args.organization)
|
||||
err := s.Delete(tt.args.ctx, tt.args.layout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("%q. LayoutsStore.All() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayouts_Get(t *testing.T) {
|
||||
type fields struct {
|
||||
LayoutsStore chronograf.LayoutsStore
|
||||
}
|
||||
type args struct {
|
||||
organization string
|
||||
ctx context.Context
|
||||
layout chronograf.Layout
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want chronograf.Layout
|
||||
addFirst bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Get Layout",
|
||||
fields: fields{
|
||||
LayoutsStore: &mocks.LayoutsStore{
|
||||
GetF: func(ctx context.Context, id string) (chronograf.Layout, error) {
|
||||
return chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
organization: "1337",
|
||||
ctx: context.Background(),
|
||||
layout: chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
},
|
||||
want: chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s := organizations.NewLayoutsStore(tt.fields.LayoutsStore, tt.args.organization)
|
||||
tt.args.ctx = context.WithValue(tt.args.ctx, organizations.ContextKey, tt.args.organization)
|
||||
got, err := s.Get(tt.args.ctx, tt.args.layout.ID)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("%q. LayoutsStore.Get() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
if diff := cmp.Diff(got, tt.want, layoutCmpOptions...); diff != "" {
|
||||
t.Errorf("%q. LayoutsStore.Get():\n-got/+want\ndiff %s", tt.name, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayouts_Update(t *testing.T) {
|
||||
type fields struct {
|
||||
LayoutsStore chronograf.LayoutsStore
|
||||
}
|
||||
type args struct {
|
||||
organization string
|
||||
ctx context.Context
|
||||
layout chronograf.Layout
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want chronograf.Layout
|
||||
addFirst bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Update Layout Application",
|
||||
fields: fields{
|
||||
LayoutsStore: &mocks.LayoutsStore{
|
||||
UpdateF: func(ctx context.Context, s chronograf.Layout) error {
|
||||
return nil
|
||||
},
|
||||
GetF: func(ctx context.Context, id string) (chronograf.Layout, error) {
|
||||
return chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "doody",
|
||||
Organization: "1337",
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
organization: "1337",
|
||||
ctx: context.Background(),
|
||||
layout: chronograf.Layout{
|
||||
ID: "1229",
|
||||
Application: "howdy",
|
||||
Organization: "1337",
|
||||
},
|
||||
name: "doody",
|
||||
},
|
||||
want: chronograf.Layout{
|
||||
Application: "doody",
|
||||
Organization: "1337",
|
||||
},
|
||||
addFirst: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if tt.args.name != "" {
|
||||
tt.args.layout.Application = tt.args.name
|
||||
}
|
||||
s := organizations.NewLayoutsStore(tt.fields.LayoutsStore, tt.args.organization)
|
||||
tt.args.ctx = context.WithValue(tt.args.ctx, organizations.ContextKey, tt.args.organization)
|
||||
err := s.Update(tt.args.ctx, tt.args.layout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("%q. LayoutsStore.Update() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
continue
|
||||
}
|
||||
got, err := s.Get(tt.args.ctx, tt.args.layout.ID)
|
||||
if diff := cmp.Diff(got, tt.want, layoutCmpOptions...); diff != "" {
|
||||
t.Errorf("%q. LayoutsStore.Update():\n-got/+want\ndiff %s", tt.name, diff)
|
||||
}
|
||||
}
|
||||
}
|
119
server/layout.go
119
server/layout.go
|
@ -1,7 +1,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
@ -49,38 +48,6 @@ func newLayoutResponse(layout chronograf.Layout) layoutResponse {
|
|||
}
|
||||
}
|
||||
|
||||
// NewLayout adds a valid layout to store.
|
||||
func (s *Service) NewLayout(w http.ResponseWriter, r *http.Request) {
|
||||
var layout chronograf.Layout
|
||||
var err error
|
||||
if err := json.NewDecoder(r.Body).Decode(&layout); err != nil {
|
||||
invalidJSON(w, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
|
||||
if err != nil {
|
||||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if err := ValidLayoutRequest(layout, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if layout, err = s.Store.Layouts(ctx).Add(r.Context(), layout); err != nil {
|
||||
msg := fmt.Errorf("Error storing layout %v: %v", layout, err)
|
||||
unknownErrorWithMessage(w, msg, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
res := newLayoutResponse(layout)
|
||||
location(w, res.Link.Href)
|
||||
encodeJSON(w, http.StatusCreated, res, s.Logger)
|
||||
}
|
||||
|
||||
type getLayoutsResponse struct {
|
||||
Layouts []layoutResponse `json:"layouts"`
|
||||
}
|
||||
|
@ -117,7 +84,14 @@ func (s *Service) Layouts(w http.ResponseWriter, r *http.Request) {
|
|||
res := getLayoutsResponse{
|
||||
Layouts: []layoutResponse{},
|
||||
}
|
||||
|
||||
seen := make(map[string]bool)
|
||||
for _, layout := range layouts {
|
||||
// remove duplicates
|
||||
if seen[layout.Measurement+layout.ID] {
|
||||
continue
|
||||
}
|
||||
// filter for data that belongs to provided application or measurement
|
||||
if filter(&layout) {
|
||||
res.Layouts = append(res.Layouts, newLayoutResponse(layout))
|
||||
}
|
||||
|
@ -139,82 +113,3 @@ func (s *Service) LayoutsID(w http.ResponseWriter, r *http.Request) {
|
|||
res := newLayoutResponse(layout)
|
||||
encodeJSON(w, http.StatusOK, res, s.Logger)
|
||||
}
|
||||
|
||||
// RemoveLayout deletes layout from store.
|
||||
func (s *Service) RemoveLayout(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
id := httprouter.GetParamFromContext(ctx, "id")
|
||||
|
||||
layout := chronograf.Layout{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
if err := s.Store.Layouts(ctx).Delete(ctx, layout); err != nil {
|
||||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// UpdateLayout replaces the layout of ID with new valid layout.
|
||||
func (s *Service) UpdateLayout(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
id := httprouter.GetParamFromContext(ctx, "id")
|
||||
|
||||
_, err := s.Store.Layouts(ctx).Get(ctx, id)
|
||||
if err != nil {
|
||||
Error(w, http.StatusNotFound, fmt.Sprintf("ID %s not found", id), s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
var req chronograf.Layout
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
invalidJSON(w, s.Logger)
|
||||
return
|
||||
}
|
||||
req.ID = id
|
||||
|
||||
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
|
||||
if err != nil {
|
||||
unknownErrorWithMessage(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if err := ValidLayoutRequest(req, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
|
||||
invalidData(w, err, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.Store.Layouts(ctx).Update(ctx, req); err != nil {
|
||||
msg := fmt.Sprintf("Error updating layout ID %s: %v", id, err)
|
||||
Error(w, http.StatusInternalServerError, msg, s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
res := newLayoutResponse(req)
|
||||
encodeJSON(w, http.StatusOK, res, s.Logger)
|
||||
}
|
||||
|
||||
// ValidLayoutRequest checks if the layout has valid application, measurement and cells.
|
||||
func ValidLayoutRequest(l chronograf.Layout, defaultOrgID string) error {
|
||||
if l.Application == "" || l.Measurement == "" || len(l.Cells) == 0 {
|
||||
return fmt.Errorf("app, measurement, and cells required")
|
||||
}
|
||||
|
||||
if l.Organization == "" {
|
||||
l.Organization = defaultOrgID
|
||||
}
|
||||
|
||||
for _, c := range l.Cells {
|
||||
if c.W == 0 || c.H == 0 {
|
||||
return fmt.Errorf("w, and h required")
|
||||
}
|
||||
for _, q := range c.Queries {
|
||||
if q.Command == "" {
|
||||
return fmt.Errorf("query required")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
package server
|
||||
|
||||
import "net/http"
|
||||
|
||||
type getMappingsResponse struct {
|
||||
Mappings []mapping `json:"mappings"`
|
||||
}
|
||||
|
||||
type mapping struct {
|
||||
Measurement string `json:"measurement"` // The measurement where data for this mapping is found
|
||||
Name string `json:"name"` // The application name which will be assigned to the corresponding measurement
|
||||
}
|
||||
|
||||
// GetMappings returns the known mappings of measurements to applications
|
||||
func (s *Service) GetMappings(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
layouts, err := s.Store.Layouts(ctx).All(ctx)
|
||||
if err != nil {
|
||||
Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
mp := getMappingsResponse{
|
||||
Mappings: []mapping{},
|
||||
}
|
||||
|
||||
seen := make(map[string]bool)
|
||||
|
||||
for _, layout := range layouts {
|
||||
if seen[layout.Measurement+layout.ID] {
|
||||
continue
|
||||
}
|
||||
mp.Mappings = append(mp.Mappings, mapping{layout.Measurement, layout.Application})
|
||||
seen[layout.Measurement+layout.ID] = true
|
||||
}
|
||||
|
||||
encodeJSON(w, http.StatusOK, mp, s.Logger)
|
||||
}
|
|
@ -183,16 +183,9 @@ func NewMux(opts MuxOpts, service Service) http.Handler {
|
|||
router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", EnsureEditor(service.KapacitorProxyPatch))
|
||||
router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", EnsureEditor(service.KapacitorProxyDelete))
|
||||
|
||||
// Mappings
|
||||
router.GET("/chronograf/v1/mappings", EnsureViewer(service.GetMappings))
|
||||
|
||||
// Layouts
|
||||
router.GET("/chronograf/v1/layouts", EnsureViewer(service.Layouts))
|
||||
router.POST("/chronograf/v1/layouts", EnsureEditor(service.NewLayout))
|
||||
|
||||
router.GET("/chronograf/v1/layouts/:id", EnsureViewer(service.LayoutsID))
|
||||
router.PUT("/chronograf/v1/layouts/:id", EnsureEditor(service.UpdateLayout))
|
||||
router.DELETE("/chronograf/v1/layouts/:id", EnsureEditor(service.RemoveLayout))
|
||||
|
||||
// Users associated with Chronograf
|
||||
router.GET("/chronograf/v1/me", service.Me)
|
||||
|
|
|
@ -130,17 +130,9 @@ func (s *Store) Servers(ctx context.Context) chronograf.ServersStore {
|
|||
return &noop.ServersStore{}
|
||||
}
|
||||
|
||||
// Layouts returns a noop.LayoutsStore if the context has no organization specified
|
||||
// and a organization.LayoutsStore otherwise.
|
||||
// Layouts returns all layouts in the underlying layouts store.
|
||||
func (s *Store) Layouts(ctx context.Context) chronograf.LayoutsStore {
|
||||
if isServer := hasServerContext(ctx); isServer {
|
||||
return s.LayoutsStore
|
||||
}
|
||||
if org, ok := hasOrganizationContext(ctx); ok {
|
||||
return organizations.NewLayoutsStore(s.LayoutsStore, org)
|
||||
}
|
||||
|
||||
return &noop.LayoutsStore{}
|
||||
return s.LayoutsStore
|
||||
}
|
||||
|
||||
// Users returns a chronograf.UsersStore.
|
||||
|
|
|
@ -110,18 +110,17 @@ export async function getAllHosts(proxyLink, telegrafDB) {
|
|||
}
|
||||
}
|
||||
|
||||
export function getMappings() {
|
||||
return AJAX({
|
||||
export const getLayouts = () =>
|
||||
AJAX({
|
||||
method: 'GET',
|
||||
resource: 'mappings',
|
||||
resource: 'layouts',
|
||||
})
|
||||
}
|
||||
|
||||
export function getAppsForHosts(proxyLink, hosts, appMappings, telegrafDB) {
|
||||
const measurements = appMappings.map(m => `^${m.measurement}$`).join('|')
|
||||
export function getAppsForHosts(proxyLink, hosts, appLayouts, telegrafDB) {
|
||||
const measurements = appLayouts.map(m => `^${m.measurement}$`).join('|')
|
||||
const measurementsToApps = _.zipObject(
|
||||
appMappings.map(m => m.measurement),
|
||||
appMappings.map(m => m.name)
|
||||
appLayouts.map(m => m.measurement),
|
||||
appLayouts.map(({app}) => app)
|
||||
)
|
||||
|
||||
return proxy({
|
||||
|
|
|
@ -13,12 +13,11 @@ import ManualRefresh from 'src/shared/components/ManualRefresh'
|
|||
|
||||
import timeRanges from 'hson!shared/data/timeRanges.hson'
|
||||
import {
|
||||
getMappings,
|
||||
getLayouts,
|
||||
getAppsForHosts,
|
||||
getMeasurementsForHost,
|
||||
getAllHosts,
|
||||
} from 'src/hosts/apis'
|
||||
import {fetchLayouts} from 'shared/apis'
|
||||
|
||||
import {setAutoRefresh} from 'shared/actions/app'
|
||||
import {presentationButtonDispatcher} from 'shared/dispatchers'
|
||||
|
@ -38,13 +37,12 @@ class HostPage extends Component {
|
|||
const {source, params, location} = this.props
|
||||
|
||||
// fetching layouts and mappings can be done at the same time
|
||||
const {data: {layouts}} = await fetchLayouts()
|
||||
const {data: {mappings}} = await getMappings()
|
||||
const {data: {layouts}} = await getLayouts()
|
||||
const hosts = await getAllHosts(source.links.proxy, source.telegraf)
|
||||
const newHosts = await getAppsForHosts(
|
||||
source.links.proxy,
|
||||
hosts,
|
||||
mappings,
|
||||
layouts,
|
||||
source.telegraf
|
||||
)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import HostsTable from 'src/hosts/components/HostsTable'
|
|||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||
|
||||
import {getCpuAndLoadForHosts, getMappings, getAppsForHosts} from '../apis'
|
||||
import {getCpuAndLoadForHosts, getLayouts, getAppsForHosts} from '../apis'
|
||||
|
||||
class HostsPage extends Component {
|
||||
constructor(props) {
|
||||
|
@ -22,18 +22,18 @@ class HostsPage extends Component {
|
|||
const {source, addFlashMessage} = this.props
|
||||
Promise.all([
|
||||
getCpuAndLoadForHosts(source.links.proxy, source.telegraf),
|
||||
getMappings(),
|
||||
getLayouts(),
|
||||
new Promise(resolve => {
|
||||
this.setState({hostsLoading: true})
|
||||
resolve()
|
||||
}),
|
||||
])
|
||||
.then(([hosts, {data: {mappings}}]) => {
|
||||
.then(([hosts, {data: {layouts}}]) => {
|
||||
this.setState({
|
||||
hosts,
|
||||
hostsLoading: false,
|
||||
})
|
||||
getAppsForHosts(source.links.proxy, hosts, mappings, source.telegraf)
|
||||
getAppsForHosts(source.links.proxy, hosts, layouts, source.telegraf)
|
||||
.then(newHosts => {
|
||||
this.setState({
|
||||
hosts: newHosts,
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
import AJAX from 'utils/ajax'
|
||||
|
||||
export function fetchLayouts() {
|
||||
return AJAX({
|
||||
url: '/chronograf/v1/layouts',
|
||||
method: 'GET',
|
||||
resource: 'layouts',
|
||||
})
|
||||
}
|
||||
|
||||
export function getSources() {
|
||||
return AJAX({
|
||||
resource: 'sources',
|
||||
|
|
|
@ -49,8 +49,15 @@
|
|||
}
|
||||
|
||||
> .btn {
|
||||
margin-top: ($sidebar--width / 2);
|
||||
margin-bottom: $sidebar--width;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: ($sidebar--width / 2);
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: $sidebar--width;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
font-size: 20px;
|
||||
|
|
Loading…
Reference in New Issue