Merge pull request #1738 from influxdata/feature/influxdb-jwt
Add JWT shared secret influxdb authpull/10616/head
commit
746d733249
|
@ -6,6 +6,7 @@
|
||||||
### Features
|
### Features
|
||||||
1. [#1717](https://github.com/influxdata/chronograf/pull/1717): View server generated TICKscripts
|
1. [#1717](https://github.com/influxdata/chronograf/pull/1717): View server generated TICKscripts
|
||||||
1. [#1681](https://github.com/influxdata/chronograf/pull/1681): Add the ability to select Custom Time Ranges in the Hostpages, Data Explorer, and Dashboards.
|
1. [#1681](https://github.com/influxdata/chronograf/pull/1681): Add the ability to select Custom Time Ranges in the Hostpages, Data Explorer, and Dashboards.
|
||||||
|
1. [#1738](https://github.com/influxdata/chronograf/pull/1738): Add shared secret JWT authorization to InfluxDB
|
||||||
|
|
||||||
|
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
|
|
|
@ -17,6 +17,7 @@ func MarshalSource(s chronograf.Source) ([]byte, error) {
|
||||||
Type: s.Type,
|
Type: s.Type,
|
||||||
Username: s.Username,
|
Username: s.Username,
|
||||||
Password: s.Password,
|
Password: s.Password,
|
||||||
|
SharedSecret: s.SharedSecret,
|
||||||
URL: s.URL,
|
URL: s.URL,
|
||||||
MetaURL: s.MetaURL,
|
MetaURL: s.MetaURL,
|
||||||
InsecureSkipVerify: s.InsecureSkipVerify,
|
InsecureSkipVerify: s.InsecureSkipVerify,
|
||||||
|
@ -37,6 +38,7 @@ func UnmarshalSource(data []byte, s *chronograf.Source) error {
|
||||||
s.Type = pb.Type
|
s.Type = pb.Type
|
||||||
s.Username = pb.Username
|
s.Username = pb.Username
|
||||||
s.Password = pb.Password
|
s.Password = pb.Password
|
||||||
|
s.SharedSecret = pb.SharedSecret
|
||||||
s.URL = pb.URL
|
s.URL = pb.URL
|
||||||
s.MetaURL = pb.MetaURL
|
s.MetaURL = pb.MetaURL
|
||||||
s.InsecureSkipVerify = pb.InsecureSkipVerify
|
s.InsecureSkipVerify = pb.InsecureSkipVerify
|
||||||
|
|
|
@ -51,6 +51,7 @@ type Source struct {
|
||||||
Telegraf string `protobuf:"bytes,8,opt,name=Telegraf,proto3" json:"Telegraf,omitempty"`
|
Telegraf string `protobuf:"bytes,8,opt,name=Telegraf,proto3" json:"Telegraf,omitempty"`
|
||||||
InsecureSkipVerify bool `protobuf:"varint,9,opt,name=InsecureSkipVerify,proto3" json:"InsecureSkipVerify,omitempty"`
|
InsecureSkipVerify bool `protobuf:"varint,9,opt,name=InsecureSkipVerify,proto3" json:"InsecureSkipVerify,omitempty"`
|
||||||
MetaURL string `protobuf:"bytes,10,opt,name=MetaURL,proto3" json:"MetaURL,omitempty"`
|
MetaURL string `protobuf:"bytes,10,opt,name=MetaURL,proto3" json:"MetaURL,omitempty"`
|
||||||
|
SharedSecret string `protobuf:"bytes,11,opt,name=SharedSecret,proto3" json:"SharedSecret,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Source) Reset() { *m = Source{} }
|
func (m *Source) Reset() { *m = Source{} }
|
||||||
|
@ -293,59 +294,60 @@ func init() {
|
||||||
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
||||||
|
|
||||||
var fileDescriptorInternal = []byte{
|
var fileDescriptorInternal = []byte{
|
||||||
// 858 bytes of a gzipped FileDescriptorProto
|
// 876 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xdd, 0x6e, 0xe3, 0x44,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x55, 0xdf, 0x6e, 0xe3, 0xc4,
|
||||||
0x14, 0xd6, 0xc4, 0x76, 0x62, 0x9f, 0xee, 0x16, 0x34, 0x5a, 0xb1, 0x06, 0x6e, 0x22, 0x0b, 0xa4,
|
0x17, 0xd6, 0xc4, 0x76, 0x62, 0x9f, 0x76, 0xfb, 0xfb, 0x69, 0xb4, 0x62, 0x0d, 0xdc, 0x44, 0x16,
|
||||||
0x82, 0x44, 0x41, 0xec, 0x13, 0xb4, 0xb5, 0x84, 0x42, 0xbb, 0x4b, 0x99, 0xb4, 0xe5, 0x0a, 0xad,
|
0x48, 0x01, 0x89, 0x82, 0xd8, 0x27, 0x68, 0x6b, 0x09, 0x85, 0x76, 0x97, 0x32, 0x69, 0xcb, 0x15,
|
||||||
0x26, 0xc9, 0x49, 0x6b, 0xed, 0x24, 0x36, 0x63, 0xbb, 0x59, 0xbf, 0x02, 0x57, 0x3c, 0x01, 0x12,
|
0x5a, 0x4d, 0x9c, 0x93, 0xc6, 0x5a, 0x27, 0x36, 0x63, 0xbb, 0x59, 0xbf, 0x05, 0x4f, 0x80, 0x84,
|
||||||
0x12, 0x57, 0x5c, 0xf2, 0x02, 0x3c, 0x04, 0x2f, 0x84, 0xce, 0xcc, 0xf8, 0x27, 0x6c, 0x41, 0x7b,
|
0xc4, 0x15, 0x17, 0x5c, 0xf0, 0x02, 0x3c, 0x04, 0x2f, 0x84, 0xce, 0xcc, 0xf8, 0x4f, 0xd8, 0x82,
|
||||||
0xb5, 0x77, 0xf3, 0x9d, 0x33, 0xf9, 0xe6, 0xfc, 0x7c, 0x9f, 0x03, 0x87, 0xd9, 0xb6, 0x42, 0xbd,
|
0xf6, 0x8a, 0xbb, 0xf9, 0xce, 0x19, 0x7f, 0xe7, 0xdf, 0x77, 0xc6, 0x70, 0x92, 0xee, 0x2a, 0x54,
|
||||||
0x95, 0xea, 0xb8, 0xd0, 0x79, 0x95, 0xf3, 0xb0, 0xc5, 0xc9, 0xcf, 0x23, 0x18, 0xcf, 0xf3, 0x5a,
|
0x3b, 0x99, 0x9d, 0x16, 0x2a, 0xaf, 0x72, 0xee, 0xb7, 0x38, 0xfa, 0x6d, 0x04, 0xe3, 0x45, 0x5e,
|
||||||
0x2f, 0x91, 0x1f, 0xc2, 0x68, 0x96, 0xc6, 0x6c, 0xca, 0x8e, 0x3c, 0x31, 0x9a, 0xa5, 0x9c, 0x83,
|
0xab, 0x04, 0xf9, 0x09, 0x8c, 0xe6, 0x71, 0xc8, 0xa6, 0x6c, 0xe6, 0x88, 0xd1, 0x3c, 0xe6, 0x1c,
|
||||||
0xff, 0x42, 0x6e, 0x30, 0x1e, 0x4d, 0xd9, 0x51, 0x24, 0xcc, 0x99, 0x62, 0x57, 0x4d, 0x81, 0xb1,
|
0xdc, 0x97, 0x72, 0x8b, 0xe1, 0x68, 0xca, 0x66, 0x81, 0xd0, 0x67, 0xb2, 0xdd, 0x34, 0x05, 0x86,
|
||||||
0x67, 0x63, 0x74, 0xe6, 0x1f, 0x41, 0x78, 0x5d, 0x12, 0xdb, 0x06, 0x63, 0xdf, 0xc4, 0x3b, 0x4c,
|
0x8e, 0xb1, 0xd1, 0x99, 0x7f, 0x00, 0xfe, 0x6d, 0x49, 0x6c, 0x5b, 0x0c, 0x5d, 0x6d, 0xef, 0x30,
|
||||||
0xb9, 0x4b, 0x59, 0x96, 0xbb, 0x5c, 0xaf, 0xe2, 0xc0, 0xe6, 0x5a, 0xcc, 0xdf, 0x07, 0xef, 0x5a,
|
0xf9, 0xae, 0x65, 0x59, 0xee, 0x73, 0xb5, 0x0a, 0x3d, 0xe3, 0x6b, 0x31, 0xff, 0x3f, 0x38, 0xb7,
|
||||||
0x5c, 0xc4, 0x63, 0x13, 0xa6, 0x23, 0x8f, 0x61, 0x92, 0xe2, 0x5a, 0xd6, 0xaa, 0x8a, 0x27, 0x53,
|
0xe2, 0x2a, 0x1c, 0x6b, 0x33, 0x1d, 0x79, 0x08, 0x93, 0x18, 0xd7, 0xb2, 0xce, 0xaa, 0x70, 0x32,
|
||||||
0x76, 0x14, 0x8a, 0x16, 0x12, 0xcf, 0x15, 0x2a, 0xbc, 0xd5, 0x72, 0x1d, 0x87, 0x96, 0xa7, 0xc5,
|
0x65, 0x33, 0x5f, 0xb4, 0x90, 0x78, 0x6e, 0x30, 0xc3, 0x7b, 0x25, 0xd7, 0xa1, 0x6f, 0x78, 0x5a,
|
||||||
0xfc, 0x18, 0xf8, 0x6c, 0x5b, 0xe2, 0xb2, 0xd6, 0x38, 0x7f, 0x95, 0x15, 0x37, 0xa8, 0xb3, 0x75,
|
0xcc, 0x4f, 0x81, 0xcf, 0x77, 0x25, 0x26, 0xb5, 0xc2, 0xc5, 0xeb, 0xb4, 0xb8, 0x43, 0x95, 0xae,
|
||||||
0x13, 0x47, 0x86, 0xe0, 0x81, 0x0c, 0xbd, 0xf2, 0x1c, 0x2b, 0x49, 0x6f, 0x83, 0xa1, 0x6a, 0x61,
|
0x9b, 0x30, 0xd0, 0x04, 0x8f, 0x78, 0x28, 0xca, 0x0b, 0xac, 0x24, 0xc5, 0x06, 0x4d, 0xd5, 0x42,
|
||||||
0xf2, 0x0b, 0x83, 0x28, 0x95, 0xe5, 0xdd, 0x22, 0x97, 0x7a, 0xf5, 0x56, 0xf3, 0xf8, 0x02, 0x82,
|
0x1e, 0xc1, 0xf1, 0x62, 0x23, 0x15, 0xae, 0x16, 0x98, 0x28, 0xac, 0xc2, 0x23, 0xed, 0x3e, 0xb0,
|
||||||
0x25, 0x2a, 0x55, 0xc6, 0xde, 0xd4, 0x3b, 0x3a, 0xf8, 0xfa, 0xe9, 0x71, 0x37, 0xe8, 0x8e, 0xe7,
|
0x45, 0x3f, 0x32, 0x08, 0x62, 0x59, 0x6e, 0x96, 0xb9, 0x54, 0xab, 0x77, 0xea, 0xd9, 0x67, 0xe0,
|
||||||
0x0c, 0x95, 0x12, 0xf6, 0x16, 0xff, 0x0a, 0xa2, 0x0a, 0x37, 0x85, 0x92, 0x15, 0x96, 0xb1, 0x6f,
|
0x25, 0x98, 0x65, 0x65, 0xe8, 0x4c, 0x9d, 0xd9, 0xd1, 0x97, 0xcf, 0x4e, 0xbb, 0x61, 0x74, 0x3c,
|
||||||
0x7e, 0xc2, 0xfb, 0x9f, 0x5c, 0xb9, 0x94, 0xe8, 0x2f, 0x25, 0x7f, 0x30, 0x78, 0xbc, 0x47, 0xc5,
|
0x17, 0x98, 0x65, 0xc2, 0xdc, 0xe2, 0x5f, 0x40, 0x50, 0xe1, 0xb6, 0xc8, 0x64, 0x85, 0x65, 0xe8,
|
||||||
0x1f, 0x01, 0x7b, 0x6d, 0xaa, 0x0a, 0x04, 0x7b, 0x4d, 0xa8, 0x31, 0x15, 0x05, 0x82, 0x35, 0x84,
|
0xea, 0x4f, 0x78, 0xff, 0xc9, 0x8d, 0x75, 0x89, 0xfe, 0x52, 0xf4, 0x2b, 0x83, 0x27, 0x07, 0x54,
|
||||||
0x76, 0x66, 0x37, 0x81, 0x60, 0x3b, 0x42, 0x77, 0x66, 0x23, 0x81, 0x60, 0x77, 0xfc, 0x33, 0x98,
|
0xfc, 0x18, 0xd8, 0x1b, 0x9d, 0x95, 0x27, 0xd8, 0x1b, 0x42, 0x8d, 0xce, 0xc8, 0x13, 0xac, 0x21,
|
||||||
0xfc, 0x54, 0xa3, 0xce, 0xb0, 0x8c, 0x03, 0xf3, 0xf2, 0x7b, 0xfd, 0xcb, 0xdf, 0xd7, 0xa8, 0x1b,
|
0xb4, 0xd7, 0xf3, 0xf3, 0x04, 0xdb, 0x13, 0xda, 0xe8, 0xa9, 0x79, 0x82, 0x6d, 0xf8, 0x27, 0x30,
|
||||||
0xd1, 0xe6, 0xa9, 0x53, 0xb3, 0x4d, 0xbb, 0x1a, 0x73, 0xa6, 0x58, 0x45, 0x9b, 0x9f, 0xd8, 0x18,
|
0xf9, 0xa1, 0x46, 0x95, 0x62, 0x19, 0x7a, 0x3a, 0xf2, 0xff, 0xfa, 0xc8, 0xdf, 0xd6, 0xa8, 0x1a,
|
||||||
0x9d, 0xdd, 0x84, 0xec, 0x3e, 0x46, 0xb3, 0x34, 0xf9, 0x8b, 0xd1, 0x9a, 0x6c, 0xe9, 0x83, 0xf1,
|
0xd1, 0xfa, 0xa9, 0x52, 0x3d, 0x71, 0x33, 0x3e, 0x7d, 0x26, 0x5b, 0x45, 0xea, 0x98, 0x18, 0x1b,
|
||||||
0x99, 0x24, 0xff, 0x10, 0x42, 0x6a, 0xeb, 0xe5, 0xbd, 0xd4, 0x6e, 0x84, 0x13, 0xc2, 0x37, 0x52,
|
0x9d, 0x6d, 0x87, 0xcc, 0xcc, 0x46, 0xf3, 0x38, 0xfa, 0x83, 0xd1, 0x28, 0x4d, 0xea, 0x83, 0xf6,
|
||||||
0xf3, 0x2f, 0x61, 0x7c, 0x2f, 0x55, 0x8d, 0x0f, 0x8c, 0xb1, 0xa5, 0xbb, 0xa1, 0xbc, 0x70, 0xd7,
|
0x69, 0x27, 0x7f, 0x1f, 0x7c, 0x2a, 0xeb, 0xd5, 0x83, 0x54, 0xb6, 0x85, 0x13, 0xc2, 0x77, 0x52,
|
||||||
0xba, 0x62, 0xfc, 0x41, 0x31, 0x4f, 0x20, 0x50, 0x72, 0x81, 0xca, 0xe9, 0xcc, 0x02, 0x5a, 0x10,
|
0xf1, 0xcf, 0x61, 0xfc, 0x20, 0xb3, 0x1a, 0x1f, 0x69, 0x63, 0x4b, 0x77, 0x47, 0x7e, 0x61, 0xaf,
|
||||||
0x75, 0xd5, 0x98, 0x5e, 0x1e, 0x64, 0xb6, 0xbd, 0xdb, 0x5b, 0xc9, 0x35, 0x3c, 0xde, 0x7b, 0xb1,
|
0x75, 0xc9, 0xb8, 0x83, 0x64, 0x9e, 0x82, 0x97, 0xc9, 0x25, 0x66, 0x56, 0x8b, 0x06, 0xd0, 0x80,
|
||||||
0x7b, 0x89, 0xed, 0xbf, 0x64, 0xea, 0x70, 0x6d, 0x58, 0x40, 0x12, 0x2d, 0x51, 0xe1, 0xb2, 0xc2,
|
0xa8, 0xaa, 0x46, 0xd7, 0xf2, 0x28, 0xb3, 0xa9, 0xdd, 0xdc, 0x8a, 0x6e, 0xe1, 0xc9, 0x41, 0xc4,
|
||||||
0x95, 0x59, 0x41, 0x28, 0x3a, 0x9c, 0xfc, 0xc6, 0x7a, 0x5e, 0xf3, 0x1e, 0x89, 0x70, 0x99, 0x6f,
|
0x2e, 0x12, 0x3b, 0x8c, 0xa4, 0xf3, 0xb0, 0x65, 0x18, 0x40, 0x32, 0x2e, 0x31, 0xc3, 0xa4, 0xc2,
|
||||||
0x36, 0x72, 0xbb, 0x72, 0xd4, 0x2d, 0xa4, 0xb9, 0xad, 0x16, 0x8e, 0x7a, 0xb4, 0x5a, 0x10, 0xd6,
|
0x95, 0x1e, 0x81, 0x2f, 0x3a, 0x1c, 0xfd, 0xcc, 0x7a, 0x5e, 0x1d, 0x8f, 0x84, 0x9a, 0xe4, 0xdb,
|
||||||
0x85, 0x33, 0xdc, 0x48, 0x17, 0x7c, 0x0a, 0x07, 0x1b, 0x94, 0x65, 0xad, 0x71, 0x83, 0xdb, 0xca,
|
0xad, 0xdc, 0xad, 0x2c, 0x75, 0x0b, 0xa9, 0x6f, 0xab, 0xa5, 0xa5, 0x1e, 0xad, 0x96, 0x84, 0x55,
|
||||||
0x8d, 0x60, 0x18, 0xe2, 0x4f, 0x61, 0x52, 0xc9, 0xdb, 0x97, 0xaf, 0xb0, 0x71, 0xb3, 0x18, 0x57,
|
0x61, 0x97, 0x72, 0xa4, 0x0a, 0x3e, 0x85, 0xa3, 0x2d, 0xca, 0xb2, 0x56, 0xb8, 0xc5, 0x5d, 0x65,
|
||||||
0xf2, 0xf6, 0x1c, 0x1b, 0xfe, 0x31, 0x44, 0xeb, 0x0c, 0xd5, 0xca, 0xa4, 0xec, 0x72, 0x43, 0x13,
|
0x5b, 0x30, 0x34, 0xf1, 0x67, 0x30, 0xa9, 0xe4, 0xfd, 0xab, 0xd7, 0xd8, 0xd8, 0x5e, 0x8c, 0x2b,
|
||||||
0x38, 0xc7, 0x26, 0xf9, 0x9d, 0xc1, 0x78, 0x8e, 0xfa, 0x1e, 0xf5, 0x5b, 0x29, 0x7f, 0xe8, 0x7a,
|
0x79, 0x7f, 0x89, 0x0d, 0xff, 0x10, 0x82, 0x75, 0x8a, 0xd9, 0x4a, 0xbb, 0xcc, 0x70, 0x7d, 0x6d,
|
||||||
0xef, 0x7f, 0x5c, 0xef, 0x3f, 0xec, 0xfa, 0xa0, 0x77, 0xfd, 0x13, 0x08, 0xe6, 0x7a, 0x39, 0x4b,
|
0xb8, 0xc4, 0x26, 0xfa, 0x85, 0xc1, 0x78, 0x81, 0xea, 0x01, 0xd5, 0x3b, 0x29, 0x7f, 0xf8, 0x32,
|
||||||
0x4d, 0x45, 0x9e, 0xb0, 0x80, 0x7f, 0x00, 0xe3, 0x93, 0x65, 0x95, 0xdd, 0xa3, 0xfb, 0x14, 0x38,
|
0x38, 0xff, 0xf2, 0x32, 0xb8, 0x8f, 0xbf, 0x0c, 0x5e, 0xff, 0x32, 0x3c, 0x05, 0x6f, 0xa1, 0x92,
|
||||||
0x94, 0xfc, 0xca, 0x60, 0x7c, 0x21, 0x9b, 0xbc, 0xae, 0xde, 0x50, 0xd8, 0x14, 0x0e, 0x4e, 0x8a,
|
0x79, 0xac, 0x33, 0x72, 0x84, 0x01, 0xfc, 0x3d, 0x18, 0x9f, 0x25, 0x55, 0xfa, 0x80, 0xf6, 0xb9,
|
||||||
0x42, 0x65, 0x4b, 0x59, 0x65, 0xf9, 0xd6, 0x55, 0x3b, 0x0c, 0xd1, 0x8d, 0xe7, 0x83, 0xd9, 0xd9,
|
0xb0, 0x28, 0xfa, 0x89, 0xc1, 0xf8, 0x4a, 0x36, 0x79, 0x5d, 0xbd, 0xa5, 0xb0, 0x29, 0x1c, 0x9d,
|
||||||
0xba, 0x87, 0x21, 0xfe, 0x09, 0x04, 0x67, 0xc6, 0xd0, 0xd6, 0x9d, 0x87, 0xbd, 0x5e, 0xac, 0x8f,
|
0x15, 0x45, 0x96, 0x26, 0xb2, 0x4a, 0xf3, 0x9d, 0xcd, 0x76, 0x68, 0xa2, 0x1b, 0x2f, 0x06, 0xbd,
|
||||||
0x4d, 0x92, 0x1a, 0x3c, 0xa9, 0xab, 0x7c, 0xad, 0xf2, 0x9d, 0xe9, 0x24, 0x14, 0x1d, 0x4e, 0xfe,
|
0x33, 0x79, 0x0f, 0x4d, 0xfc, 0x23, 0xf0, 0x2e, 0xf4, 0x42, 0x9b, 0xed, 0x3c, 0xe9, 0xf5, 0x62,
|
||||||
0x66, 0xe0, 0xbf, 0x2b, 0xa3, 0x3e, 0x02, 0x96, 0xb9, 0x45, 0xb2, 0xac, 0xb3, 0xed, 0x64, 0x60,
|
0xf6, 0x58, 0x3b, 0xa9, 0xc0, 0xb3, 0xba, 0xca, 0xd7, 0x59, 0xbe, 0xd7, 0x95, 0xf8, 0xa2, 0xc3,
|
||||||
0xdb, 0x18, 0x26, 0x8d, 0x96, 0xdb, 0x5b, 0x2c, 0xe3, 0x70, 0xea, 0x1d, 0x79, 0xa2, 0x85, 0x26,
|
0xd1, 0x9f, 0x0c, 0xdc, 0xff, 0x6a, 0x51, 0x8f, 0x81, 0xa5, 0x76, 0x90, 0x2c, 0xed, 0xd6, 0x76,
|
||||||
0x63, 0x3c, 0x52, 0xc6, 0xd1, 0xd4, 0x23, 0x05, 0x3a, 0xd8, 0x69, 0x1e, 0x7a, 0xcd, 0x27, 0x7f,
|
0x32, 0x58, 0xdb, 0x10, 0x26, 0x8d, 0x92, 0xbb, 0x7b, 0x2c, 0x43, 0x7f, 0xea, 0xcc, 0x1c, 0xd1,
|
||||||
0x32, 0x08, 0x3a, 0xe5, 0x9e, 0xed, 0x2b, 0xf7, 0xac, 0x57, 0x6e, 0x7a, 0xda, 0x2a, 0x37, 0x3d,
|
0x42, 0xed, 0xd1, 0x3b, 0x52, 0x86, 0xc1, 0xd4, 0x21, 0x05, 0x5a, 0xd8, 0x69, 0x1e, 0x7a, 0xcd,
|
||||||
0x25, 0x2c, 0x2e, 0x5b, 0xe5, 0x8a, 0x4b, 0x9a, 0xda, 0x37, 0x3a, 0xaf, 0x8b, 0xd3, 0xc6, 0x8e,
|
0x47, 0xbf, 0x33, 0xf0, 0x3a, 0xe5, 0x5e, 0x1c, 0x2a, 0xf7, 0xa2, 0x57, 0x6e, 0x7c, 0xde, 0x2a,
|
||||||
0x37, 0x12, 0x1d, 0xa6, 0x75, 0xff, 0x70, 0x87, 0xda, 0xf5, 0x1c, 0x09, 0x87, 0x48, 0x1c, 0x17,
|
0x37, 0x3e, 0x27, 0x2c, 0xae, 0x5b, 0xe5, 0x8a, 0x6b, 0xea, 0xda, 0x57, 0x2a, 0xaf, 0x8b, 0xf3,
|
||||||
0xc6, 0xd5, 0xb6, 0x4b, 0x0b, 0xf8, 0xa7, 0x10, 0x08, 0xea, 0xc2, 0xb4, 0xba, 0x37, 0x20, 0x13,
|
0xc6, 0xb4, 0x37, 0x10, 0x1d, 0xa6, 0x71, 0x7f, 0xb7, 0x41, 0x65, 0x6b, 0x0e, 0x84, 0x45, 0x24,
|
||||||
0x16, 0x36, 0x9b, 0x3c, 0x73, 0xd7, 0x88, 0xe5, 0xba, 0x28, 0x50, 0x3b, 0x4d, 0x5b, 0x60, 0xb8,
|
0x8e, 0x2b, 0xbd, 0xd5, 0xa6, 0x4a, 0x03, 0xf8, 0xc7, 0xe0, 0x09, 0xaa, 0x42, 0x97, 0x7a, 0xd0,
|
||||||
0xf3, 0x1d, 0xda, 0xcf, 0x91, 0x27, 0x2c, 0x48, 0x7e, 0x84, 0xe8, 0x44, 0xa1, 0xae, 0x44, 0xad,
|
0x20, 0x6d, 0x16, 0xc6, 0x1b, 0x3d, 0xb7, 0xd7, 0x88, 0xe5, 0xb6, 0x28, 0x50, 0x59, 0x4d, 0x1b,
|
||||||
0xde, 0xfc, 0x88, 0x71, 0xf0, 0xbf, 0x9d, 0x7f, 0xf7, 0xa2, 0x75, 0x02, 0x9d, 0x7b, 0xfd, 0x7a,
|
0xa0, 0xb9, 0xf3, 0x3d, 0x9a, 0xe7, 0xc8, 0x11, 0x06, 0x44, 0xdf, 0x43, 0x70, 0x96, 0xa1, 0xaa,
|
||||||
0xff, 0xd2, 0xef, 0xb9, 0x2c, 0xe4, 0x2c, 0x35, 0x8b, 0xf5, 0x84, 0x43, 0xc9, 0xe7, 0xe0, 0x93,
|
0x44, 0x9d, 0xbd, 0xfd, 0x88, 0x71, 0x70, 0xbf, 0x5e, 0x7c, 0xf3, 0xb2, 0xdd, 0x04, 0x3a, 0xf7,
|
||||||
0x4f, 0x06, 0xcc, 0xfe, 0x7f, 0x79, 0x6c, 0x31, 0x36, 0xff, 0xd6, 0xcf, 0xfe, 0x09, 0x00, 0x00,
|
0xfa, 0x75, 0xfe, 0xa6, 0xdf, 0x4b, 0x59, 0xc8, 0x79, 0xac, 0x07, 0xeb, 0x08, 0x8b, 0xa2, 0x4f,
|
||||||
0xff, 0xff, 0xa7, 0xc6, 0x53, 0x22, 0xbf, 0x07, 0x00, 0x00,
|
0xc1, 0xa5, 0x3d, 0x19, 0x30, 0xbb, 0xff, 0xb4, 0x63, 0xcb, 0xb1, 0xfe, 0xa3, 0x3f, 0xff, 0x2b,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0x0f, 0x40, 0x84, 0xea, 0xe3, 0x07, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ message Source {
|
||||||
string Telegraf = 8; // Telegraf is the db telegraf is written to. By default it is "telegraf"
|
string Telegraf = 8; // Telegraf is the db telegraf is written to. By default it is "telegraf"
|
||||||
bool InsecureSkipVerify = 9; // InsecureSkipVerify accepts any certificate from the influx server
|
bool InsecureSkipVerify = 9; // InsecureSkipVerify accepts any certificate from the influx server
|
||||||
string MetaURL = 10; // MetaURL is the connection URL for the meta node.
|
string MetaURL = 10; // MetaURL is the connection URL for the meta node.
|
||||||
|
string SharedSecret = 11; // SharedSecret signs the optional InfluxDB JWT Authorization
|
||||||
}
|
}
|
||||||
|
|
||||||
message Dashboard {
|
message Dashboard {
|
||||||
|
|
|
@ -40,6 +40,38 @@ func TestMarshalSource(t *testing.T) {
|
||||||
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, v)
|
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func TestMarshalSourceWithSecret(t *testing.T) {
|
||||||
|
v := chronograf.Source{
|
||||||
|
ID: 12,
|
||||||
|
Name: "Fountain of Truth",
|
||||||
|
Type: "influx",
|
||||||
|
Username: "docbrown",
|
||||||
|
SharedSecret: "hunter2s",
|
||||||
|
URL: "http://twin-pines.mall.io:8086",
|
||||||
|
MetaURL: "http://twin-pines.meta.io:8086",
|
||||||
|
Default: true,
|
||||||
|
Telegraf: "telegraf",
|
||||||
|
}
|
||||||
|
|
||||||
|
var vv chronograf.Source
|
||||||
|
if buf, err := internal.MarshalSource(v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if err := internal.UnmarshalSource(buf, &vv); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if !reflect.DeepEqual(v, vv) {
|
||||||
|
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if the new insecureskipverify works
|
||||||
|
v.InsecureSkipVerify = true
|
||||||
|
if buf, err := internal.MarshalSource(v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if err := internal.UnmarshalSource(buf, &vv); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if !reflect.DeepEqual(v, vv) {
|
||||||
|
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMarshalServer(t *testing.T) {
|
func TestMarshalServer(t *testing.T) {
|
||||||
v := chronograf.Server{
|
v := chronograf.Server{
|
||||||
|
|
|
@ -346,6 +346,7 @@ type Source struct {
|
||||||
Type string `json:"type,omitempty"` // Type specifies which kinds of source (enterprise vs oss)
|
Type string `json:"type,omitempty"` // Type specifies which kinds of source (enterprise vs oss)
|
||||||
Username string `json:"username,omitempty"` // Username is the username to connect to the source
|
Username string `json:"username,omitempty"` // Username is the username to connect to the source
|
||||||
Password string `json:"password,omitempty"` // Password is in CLEARTEXT
|
Password string `json:"password,omitempty"` // Password is in CLEARTEXT
|
||||||
|
SharedSecret string `json:"sharedSecret,omitempty"` // ShareSecret is the optional signing secret for Influx JWT authorization
|
||||||
URL string `json:"url"` // URL are the connections to the source
|
URL string `json:"url"` // URL are the connections to the source
|
||||||
MetaURL string `json:"metaUrl,omitempty"` // MetaURL is the url for the meta node
|
MetaURL string `json:"metaUrl,omitempty"` // MetaURL is the url for the meta node
|
||||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` // InsecureSkipVerify as true means any certificate presented by the source is accepted.
|
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` // InsecureSkipVerify as true means any certificate presented by the source is accepted.
|
||||||
|
@ -625,44 +626,3 @@ type LayoutStore interface {
|
||||||
// Update the dashboard in the store.
|
// Update the dashboard in the store.
|
||||||
Update(context.Context, Layout) error
|
Update(context.Context, Layout) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// SourceAndKapacitor is used to parse any NewSources server flag arguments
|
|
||||||
type SourceAndKapacitor struct {
|
|
||||||
Source Source `json:"influxdb"`
|
|
||||||
Kapacitor Server `json:"kapacitor"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSources adds sources to BoltDb idempotently by name, as well as respective kapacitors
|
|
||||||
func NewSources(ctx context.Context, sourcesStore SourcesStore, serversStore ServersStore, srcsKaps []SourceAndKapacitor, logger Logger) error {
|
|
||||||
srcs, err := sourcesStore.All(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLoop:
|
|
||||||
for _, srcKap := range srcsKaps {
|
|
||||||
for _, src := range srcs {
|
|
||||||
// If source already exists, do nothing
|
|
||||||
if src.Name == srcKap.Source.Name {
|
|
||||||
logger.
|
|
||||||
WithField("component", "server").
|
|
||||||
WithField("NewSources", src.Name).
|
|
||||||
Info("Source already exists")
|
|
||||||
continue SourceLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
src, err := sourcesStore.Add(ctx, srcKap.Source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
srcKap.Kapacitor.SrcID = src.ID
|
|
||||||
_, err = serversStore.Add(ctx, srcKap.Kapacitor)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
package chronograf_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/influxdata/chronograf"
|
|
||||||
"github.com/influxdata/chronograf/mocks"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_NewSources(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
srcsKaps := []chronograf.SourceAndKapacitor{
|
|
||||||
{
|
|
||||||
Source: chronograf.Source{
|
|
||||||
Default: true,
|
|
||||||
InsecureSkipVerify: false,
|
|
||||||
MetaURL: "http://metaurl.com",
|
|
||||||
Name: "Influx 1",
|
|
||||||
Password: "pass1",
|
|
||||||
Telegraf: "telegraf",
|
|
||||||
URL: "http://localhost:8086",
|
|
||||||
Username: "user1",
|
|
||||||
},
|
|
||||||
Kapacitor: chronograf.Server{
|
|
||||||
Active: true,
|
|
||||||
Name: "Kapa 1",
|
|
||||||
URL: "http://localhost:9092",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
saboteurSrcsKaps := []chronograf.SourceAndKapacitor{
|
|
||||||
{
|
|
||||||
Source: chronograf.Source{
|
|
||||||
Name: "Influx 1",
|
|
||||||
},
|
|
||||||
Kapacitor: chronograf.Server{
|
|
||||||
Name: "Kapa Aspiring Saboteur",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
srcs := []chronograf.Source{}
|
|
||||||
srcsStore := mocks.SourcesStore{
|
|
||||||
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
|
|
||||||
return srcs, nil
|
|
||||||
},
|
|
||||||
AddF: func(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
|
||||||
srcs = append(srcs, src)
|
|
||||||
return src, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
srvs := []chronograf.Server{}
|
|
||||||
srvsStore := mocks.ServersStore{
|
|
||||||
AddF: func(ctx context.Context, srv chronograf.Server) (chronograf.Server, error) {
|
|
||||||
srvs = append(srvs, srv)
|
|
||||||
return srv, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := chronograf.NewSources(ctx, &srcsStore, &srvsStore, srcsKaps, &mocks.TestLogger{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Expected no error when creating New Sources. Error:", err)
|
|
||||||
}
|
|
||||||
if len(srcs) != 1 {
|
|
||||||
t.Error("Expected one source in sourcesStore")
|
|
||||||
}
|
|
||||||
if len(srvs) != 1 {
|
|
||||||
t.Error("Expected one source in serversStore")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = chronograf.NewSources(ctx, &srcsStore, &srvsStore, saboteurSrcsKaps, &mocks.TestLogger{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Expected no error when creating New Sources. Error:", err)
|
|
||||||
}
|
|
||||||
if len(srcs) != 1 {
|
|
||||||
t.Error("Expected one source in sourcesStore")
|
|
||||||
}
|
|
||||||
if len(srvs) != 1 {
|
|
||||||
t.Error("Expected one source in serversStore")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(srcs[0], srcsKaps[0].Source) {
|
|
||||||
t.Error("Expected source in sourceStore to remain unchanged")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -120,14 +120,18 @@ func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
|
||||||
c.dataNodes = ring.New(len(cluster.DataNodes))
|
c.dataNodes = ring.New(len(cluster.DataNodes))
|
||||||
for _, dn := range cluster.DataNodes {
|
for _, dn := range cluster.DataNodes {
|
||||||
cl, err := influx.NewClient(dn.HTTPAddr, c.Logger)
|
cl := &influx.Client{
|
||||||
if err != nil {
|
Logger: c.Logger,
|
||||||
|
}
|
||||||
|
dataSrc := &chronograf.Source{}
|
||||||
|
*dataSrc = *src
|
||||||
|
dataSrc.URL = dn.HTTPAddr
|
||||||
|
if err := cl.Connect(ctx, dataSrc); err != nil {
|
||||||
continue
|
continue
|
||||||
} else {
|
}
|
||||||
c.dataNodes.Value = cl
|
c.dataNodes.Value = cl
|
||||||
c.dataNodes = c.dataNodes.Next()
|
c.dataNodes = c.dataNodes.Next()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,27 +28,11 @@ var (
|
||||||
// Client is a device for retrieving time series data from an InfluxDB instance
|
// Client is a device for retrieving time series data from an InfluxDB instance
|
||||||
type Client struct {
|
type Client struct {
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
|
Bearer Bearer
|
||||||
InsecureSkipVerify bool
|
InsecureSkipVerify bool
|
||||||
|
|
||||||
Logger chronograf.Logger
|
Logger chronograf.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient initializes an HTTP Client for InfluxDB. UDP, although supported
|
|
||||||
// for querying InfluxDB, is not supported here to remove the need to
|
|
||||||
// explicitly Close the client.
|
|
||||||
func NewClient(host string, lg chronograf.Logger) (*Client, error) {
|
|
||||||
l := lg.WithField("host", host)
|
|
||||||
u, err := url.Parse(host)
|
|
||||||
if err != nil {
|
|
||||||
l.Error("Error initialize influx client: err:", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Client{
|
|
||||||
URL: u,
|
|
||||||
Logger: l,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response is a partial JSON decoded InfluxQL response used
|
// Response is a partial JSON decoded InfluxQL response used
|
||||||
// to check for some errors
|
// to check for some errors
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
@ -88,6 +72,15 @@ func (c *Client) query(u *url.URL, q chronograf.Query) (chronograf.Response, err
|
||||||
params.Set("epoch", "ms") // TODO(timraymond): set this based on analysis
|
params.Set("epoch", "ms") // TODO(timraymond): set this based on analysis
|
||||||
req.URL.RawQuery = params.Encode()
|
req.URL.RawQuery = params.Encode()
|
||||||
|
|
||||||
|
if c.Bearer != nil && u.User != nil {
|
||||||
|
token, err := c.Bearer.Token(u.User.Username())
|
||||||
|
if err != nil {
|
||||||
|
logs.Error("Error creating token", err)
|
||||||
|
return nil, fmt.Errorf("Unable to create token")
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
}
|
||||||
|
|
||||||
hc := &http.Client{}
|
hc := &http.Client{}
|
||||||
if c.InsecureSkipVerify {
|
if c.InsecureSkipVerify {
|
||||||
hc.Transport = skipVerifyTransport
|
hc.Transport = skipVerifyTransport
|
||||||
|
@ -157,7 +150,7 @@ func (c *Client) Query(ctx context.Context, q chronograf.Query) (chronograf.Resp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect caches the URL for the data source
|
// Connect caches the URL and optional Bearer Authorization for the data source
|
||||||
func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
|
func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
|
||||||
u, err := url.Parse(src.URL)
|
u, err := url.Parse(src.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -169,6 +162,16 @@ func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
|
||||||
c.InsecureSkipVerify = src.InsecureSkipVerify
|
c.InsecureSkipVerify = src.InsecureSkipVerify
|
||||||
}
|
}
|
||||||
c.URL = u
|
c.URL = u
|
||||||
|
|
||||||
|
// Optionally, add the shared secret JWT token creation
|
||||||
|
if src.Username != "" && src.SharedSecret != "" {
|
||||||
|
c.Bearer = &BearerJWT{
|
||||||
|
src.SharedSecret,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Clear out the bearer if not needed
|
||||||
|
c.Bearer = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,34 @@ package influx_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
gojwt "github.com/dgrijalva/jwt-go"
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
"github.com/influxdata/chronograf/influx"
|
"github.com/influxdata/chronograf/influx"
|
||||||
"github.com/influxdata/chronograf/log"
|
"github.com/influxdata/chronograf/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewClient initializes an HTTP Client for InfluxDB.
|
||||||
|
func NewClient(host string, lg chronograf.Logger) (*influx.Client, error) {
|
||||||
|
l := lg.WithField("host", host)
|
||||||
|
u, err := url.Parse(host)
|
||||||
|
if err != nil {
|
||||||
|
l.Error("Error initialize influx client: err:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &influx.Client{
|
||||||
|
URL: u,
|
||||||
|
Logger: l,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Influx_MakesRequestsToQueryEndpoint(t *testing.T) {
|
func Test_Influx_MakesRequestsToQueryEndpoint(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
called := false
|
called := false
|
||||||
|
@ -26,7 +44,7 @@ func Test_Influx_MakesRequestsToQueryEndpoint(t *testing.T) {
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
var series chronograf.TimeSeries
|
var series chronograf.TimeSeries
|
||||||
series, err := influx.NewClient(ts.URL, log.New(log.DebugLevel))
|
series, err := NewClient(ts.URL, log.New(log.DebugLevel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error initializing client: err:", err)
|
t.Fatal("Unexpected error initializing client: err:", err)
|
||||||
}
|
}
|
||||||
|
@ -44,6 +62,126 @@ func Test_Influx_MakesRequestsToQueryEndpoint(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MockBearer struct {
|
||||||
|
Bearer string
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockBearer) Token(username string) (string, error) {
|
||||||
|
return m.Bearer, m.Error
|
||||||
|
}
|
||||||
|
func Test_Influx_AuthorizationBearer(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
want := "Bearer ********"
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
rw.Write([]byte(`{}`))
|
||||||
|
got := r.Header.Get("Authorization")
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Test_Influx_AuthorizationBearer got %s want %s", got, want)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
bearer := &MockBearer{
|
||||||
|
Bearer: "********",
|
||||||
|
}
|
||||||
|
|
||||||
|
u, _ := url.Parse(ts.URL)
|
||||||
|
u.User = url.UserPassword("AzureDiamond", "hunter2")
|
||||||
|
series := &influx.Client{
|
||||||
|
URL: u,
|
||||||
|
Bearer: bearer,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
query := chronograf.Query{
|
||||||
|
Command: "show databases",
|
||||||
|
}
|
||||||
|
_, err := series.Query(context.Background(), query)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error but was", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Influx_AuthorizationBearerCtx(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
rw.Write([]byte(`{}`))
|
||||||
|
got := r.Header.Get("Authorization")
|
||||||
|
if got == "" {
|
||||||
|
t.Error("Test_Influx_AuthorizationBearerCtx got empty string")
|
||||||
|
}
|
||||||
|
incomingToken := strings.Split(got, " ")[1]
|
||||||
|
|
||||||
|
alg := func(token *gojwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := token.Method.(*gojwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
return []byte("hunter2"), nil
|
||||||
|
}
|
||||||
|
claims := &gojwt.MapClaims{}
|
||||||
|
token, err := gojwt.ParseWithClaims(string(incomingToken), claims, alg)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test_Influx_AuthorizationBearerCtx unexpected claims error %v", err)
|
||||||
|
}
|
||||||
|
if !token.Valid {
|
||||||
|
t.Error("Test_Influx_AuthorizationBearerCtx unexpected valid claim")
|
||||||
|
}
|
||||||
|
if err := claims.Valid(); err != nil {
|
||||||
|
t.Errorf("Test_Influx_AuthorizationBearerCtx not expires already %v", err)
|
||||||
|
}
|
||||||
|
user := (*claims)["username"].(string)
|
||||||
|
if user != "AzureDiamond" {
|
||||||
|
t.Errorf("Test_Influx_AuthorizationBearerCtx expected username AzureDiamond but got %s", user)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
series := &influx.Client{
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := series.Connect(context.Background(), &chronograf.Source{
|
||||||
|
Username: "AzureDiamond",
|
||||||
|
SharedSecret: "hunter2",
|
||||||
|
URL: ts.URL,
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
query := chronograf.Query{
|
||||||
|
Command: "show databases",
|
||||||
|
}
|
||||||
|
_, err = series.Query(context.Background(), query)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error but was", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Influx_AuthorizationBearerFailure(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
bearer := &MockBearer{
|
||||||
|
Error: fmt.Errorf("cracked1337"),
|
||||||
|
}
|
||||||
|
|
||||||
|
u, _ := url.Parse("http://haxored.net")
|
||||||
|
u.User = url.UserPassword("AzureDiamond", "hunter2")
|
||||||
|
series := &influx.Client{
|
||||||
|
URL: u,
|
||||||
|
Bearer: bearer,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
query := chronograf.Query{
|
||||||
|
Command: "show databases",
|
||||||
|
}
|
||||||
|
_, err := series.Query(context.Background(), query)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Test_Influx_AuthorizationBearerFailure Expected error but received nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Influx_HTTPS_Failure(t *testing.T) {
|
func Test_Influx_HTTPS_Failure(t *testing.T) {
|
||||||
called := false
|
called := false
|
||||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -53,7 +191,7 @@ func Test_Influx_HTTPS_Failure(t *testing.T) {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
var series chronograf.TimeSeries
|
var series chronograf.TimeSeries
|
||||||
series, err := influx.NewClient(ts.URL, log.New(log.DebugLevel))
|
series, err := NewClient(ts.URL, log.New(log.DebugLevel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error initializing client: err:", err)
|
t.Fatal("Unexpected error initializing client: err:", err)
|
||||||
}
|
}
|
||||||
|
@ -97,7 +235,7 @@ func Test_Influx_HTTPS_InsecureSkipVerify(t *testing.T) {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
var series chronograf.TimeSeries
|
var series chronograf.TimeSeries
|
||||||
series, err := influx.NewClient(ts.URL, log.New(log.DebugLevel))
|
series, err := NewClient(ts.URL, log.New(log.DebugLevel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error initializing client: err:", err)
|
t.Fatal("Unexpected error initializing client: err:", err)
|
||||||
}
|
}
|
||||||
|
@ -166,7 +304,7 @@ func Test_Influx_CancelsInFlightRequests(t *testing.T) {
|
||||||
ts.Close()
|
ts.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
series, _ := influx.NewClient(ts.URL, log.New(log.DebugLevel))
|
series, _ := NewClient(ts.URL, log.New(log.DebugLevel))
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
errs := make(chan (error))
|
errs := make(chan (error))
|
||||||
|
@ -209,7 +347,7 @@ func Test_Influx_CancelsInFlightRequests(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Influx_RejectsInvalidHosts(t *testing.T) {
|
func Test_Influx_RejectsInvalidHosts(t *testing.T) {
|
||||||
_, err := influx.NewClient(":", log.New(log.DebugLevel))
|
_, err := NewClient(":", log.New(log.DebugLevel))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expected err but was nil")
|
t.Fatal("Expected err but was nil")
|
||||||
}
|
}
|
||||||
|
@ -221,7 +359,7 @@ func Test_Influx_ReportsInfluxErrs(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
cl, err := influx.NewClient(ts.URL, log.New(log.DebugLevel))
|
cl, err := NewClient(ts.URL, log.New(log.DebugLevel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Encountered unexpected error while initializing influx client: err:", err)
|
t.Fatal("Encountered unexpected error while initializing influx client: err:", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package influx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bearer generates tokens for Authorization: Bearer
|
||||||
|
type Bearer interface {
|
||||||
|
Token(username string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BearerJWT is the default Bearer for InfluxDB
|
||||||
|
type BearerJWT struct {
|
||||||
|
SharedSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token returns the expected InfluxDB JWT signed with the sharedSecret
|
||||||
|
func (b *BearerJWT) Token(username string) (string, error) {
|
||||||
|
return JWT(username, b.SharedSecret, time.Now)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now returns the current time
|
||||||
|
type Now func() time.Time
|
||||||
|
|
||||||
|
// JWT returns a token string accepted by InfluxDB using the sharedSecret as an Authorization: Bearer header
|
||||||
|
func JWT(username, sharedSecret string, now Now) (string, error) {
|
||||||
|
token := &jwt.Token{
|
||||||
|
Header: map[string]interface{}{
|
||||||
|
"typ": "JWT",
|
||||||
|
"alg": jwt.SigningMethodHS512.Alg(),
|
||||||
|
},
|
||||||
|
Claims: jwt.MapClaims{
|
||||||
|
"username": username,
|
||||||
|
"exp": now().Add(time.Minute).Unix(),
|
||||||
|
},
|
||||||
|
Method: jwt.SigningMethodHS512,
|
||||||
|
}
|
||||||
|
return token.SignedString([]byte(sharedSecret))
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package influx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJWT(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
username string
|
||||||
|
sharedSecret string
|
||||||
|
now Now
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
args: args{
|
||||||
|
username: "AzureDiamond",
|
||||||
|
sharedSecret: "hunter2",
|
||||||
|
now: func() time.Time {
|
||||||
|
return time.Unix(0, 0)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjYwLCJ1c2VybmFtZSI6IkF6dXJlRGlhbW9uZCJ9.kUWGwcpCPwV7MEk7luO1rt8036LyvG4bRL_CfseQGmz4b0S34gATx30g4xvqVAV6bwwYE0YU3P8FjG8ij4kc5g",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := JWT(tt.args.username, tt.args.sharedSecret, tt.args.now)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("JWT() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("JWT() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package server
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
@ -51,7 +50,7 @@ type Server struct {
|
||||||
KapacitorUsername string `long:"kapacitor-username" description:"Username of your Kapacitor instance" env:"KAPACITOR_USERNAME"`
|
KapacitorUsername string `long:"kapacitor-username" description:"Username of your Kapacitor instance" env:"KAPACITOR_USERNAME"`
|
||||||
KapacitorPassword string `long:"kapacitor-password" description:"Password of your Kapacitor instance" env:"KAPACITOR_PASSWORD"`
|
KapacitorPassword string `long:"kapacitor-password" description:"Password of your Kapacitor instance" env:"KAPACITOR_PASSWORD"`
|
||||||
|
|
||||||
NewSources string `long:"new-sources" description:"Config for adding a new InfluxDb source and Kapacitor server, in JSON as an array of objects, and surrounded by single quotes. E.g. --new-sources='[{\"influxdb\":{\"name\":\"Influx 1\",\"username\":\"user1\",\"password\":\"pass1\",\"url\":\"http://localhost:8086\",\"metaUrl\":\"http://metaurl.com\",\"insecureSkipVerify\":false,\"default\":true,\"telegraf\":\"telegraf\"},\"kapacitor\":{\"name\":\"Kapa 1\",\"url\":\"http://localhost:9092\",\"active\":true}}]'" env:"NEW_SOURCES"`
|
NewSources string `long:"new-sources" description:"Config for adding a new InfluxDB source and Kapacitor server, in JSON as an array of objects, and surrounded by single quotes. E.g. --new-sources='[{\"influxdb\":{\"name\":\"Influx 1\",\"username\":\"user1\",\"password\":\"pass1\",\"url\":\"http://localhost:8086\",\"metaUrl\":\"http://metaurl.com\",\"insecureSkipVerify\":false,\"default\":true,\"telegraf\":\"telegraf\",\"sharedSecret\":\"hunter2\"},\"kapacitor\":{\"name\":\"Kapa 1\",\"url\":\"http://localhost:9092\",\"active\":true}}]'" env:"NEW_SOURCES" hidden:"true"`
|
||||||
|
|
||||||
Develop bool `short:"d" long:"develop" description:"Run server in develop mode."`
|
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 (/var/lib/chronograf/chronograf-v1.db)" env:"BOLT_PATH" default:"chronograf-v1.db"`
|
BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (/var/lib/chronograf/chronograf-v1.db)" env:"BOLT_PATH" default:"chronograf-v1.db"`
|
||||||
|
@ -301,8 +300,13 @@ func (s *Server) Serve(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
service := openService(ctx, s.BoltPath, layoutBuilder, sourcesBuilder, kapacitorBuilder, logger, s.useAuth())
|
service := openService(ctx, s.BoltPath, layoutBuilder, sourcesBuilder, kapacitorBuilder, logger, s.useAuth())
|
||||||
|
if err := service.HandleNewSources(ctx, s.NewSources); err != nil {
|
||||||
go processNewSources(ctx, service, s.NewSources, logger)
|
logger.
|
||||||
|
WithField("component", "server").
|
||||||
|
WithField("new-sources", "invalid").
|
||||||
|
Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
basepath = s.Basepath
|
basepath = s.Basepath
|
||||||
if basepath != "" && s.PrefixRoutes == false {
|
if basepath != "" && s.PrefixRoutes == false {
|
||||||
|
@ -437,33 +441,6 @@ func openService(ctx context.Context, boltPath string, lBuilder LayoutBuilder, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// processNewSources parses and persists new sources passed in via server flag
|
|
||||||
func processNewSources(ctx context.Context, service Service, newSources string, logger chronograf.Logger) error {
|
|
||||||
if newSources == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var srcsKaps []chronograf.SourceAndKapacitor
|
|
||||||
// On JSON unmarshal error, continue server process without new source and write error to log
|
|
||||||
if err := json.Unmarshal([]byte(newSources), &srcsKaps); err != nil {
|
|
||||||
logger.
|
|
||||||
WithField("component", "server").
|
|
||||||
WithField("NewSources", "invalid").
|
|
||||||
Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add any new sources and kapacitors as specified via server flag
|
|
||||||
if err := chronograf.NewSources(ctx, service.SourcesStore, service.ServersStore, srcsKaps, logger); err != nil {
|
|
||||||
// Continue with server run even if adding NewSources fails
|
|
||||||
logger.
|
|
||||||
WithField("component", "server").
|
|
||||||
WithField("NewSources", "invalid").
|
|
||||||
Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// reportUsageStats starts periodic server reporting.
|
// reportUsageStats starts periodic server reporting.
|
||||||
func reportUsageStats(bi BuildInfo, logger chronograf.Logger) {
|
func reportUsageStats(bi BuildInfo, logger chronograf.Logger) {
|
||||||
rand.Seed(time.Now().UTC().UnixNano())
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
|
|
|
@ -43,18 +43,15 @@ type InfluxClient struct{}
|
||||||
|
|
||||||
// New creates a client to connect to OSS or enterprise
|
// New creates a client to connect to OSS or enterprise
|
||||||
func (c *InfluxClient) New(src chronograf.Source, logger chronograf.Logger) (chronograf.TimeSeries, error) {
|
func (c *InfluxClient) New(src chronograf.Source, logger chronograf.Logger) (chronograf.TimeSeries, error) {
|
||||||
if src.Type == chronograf.InfluxEnterprise && src.MetaURL != "" {
|
client := &influx.Client{
|
||||||
dataNode := &influx.Client{
|
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
}
|
}
|
||||||
if err := dataNode.Connect(context.TODO(), &src); err != nil {
|
if err := client.Connect(context.TODO(), &src); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if src.Type == chronograf.InfluxEnterprise && src.MetaURL != "" {
|
||||||
tls := strings.Contains(src.MetaURL, "https")
|
tls := strings.Contains(src.MetaURL, "https")
|
||||||
return enterprise.NewClientWithTimeSeries(logger, src.MetaURL, src.Username, src.Password, tls, dataNode)
|
return enterprise.NewClientWithTimeSeries(logger, src.MetaURL, src.Username, src.Password, tls, client)
|
||||||
}
|
}
|
||||||
return &influx.Client{
|
return client, nil
|
||||||
Logger: logger,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ func newSourceResponse(src chronograf.Source) sourceResponse {
|
||||||
src.Telegraf = "telegraf"
|
src.Telegraf = "telegraf"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Omit the password on response
|
// Omit the password and shared secret on response
|
||||||
src.Password = ""
|
src.Password = ""
|
||||||
|
src.SharedSecret = ""
|
||||||
|
|
||||||
httpAPISrcs := "/chronograf/v1/sources"
|
httpAPISrcs := "/chronograf/v1/sources"
|
||||||
res := sourceResponse{
|
res := sourceResponse{
|
||||||
|
@ -99,6 +100,7 @@ func (h *Service) tsdbType(ctx context.Context, src *chronograf.Source) (string,
|
||||||
cli := &influx.Client{
|
cli := &influx.Client{
|
||||||
Logger: h.Logger,
|
Logger: h.Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cli.Connect(ctx, src); err != nil {
|
if err := cli.Connect(ctx, src); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -293,3 +295,69 @@ func ValidSourceRequest(s chronograf.Source) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleNewSources parses and persists new sources passed in via server flag
|
||||||
|
func (h *Service) HandleNewSources(ctx context.Context, input string) error {
|
||||||
|
if input == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcsKaps []struct {
|
||||||
|
Source chronograf.Source `json:"influxdb"`
|
||||||
|
Kapacitor chronograf.Server `json:"kapacitor"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(input), &srcsKaps); err != nil {
|
||||||
|
h.Logger.
|
||||||
|
WithField("component", "server").
|
||||||
|
WithField("NewSources", "invalid").
|
||||||
|
Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sk := range srcsKaps {
|
||||||
|
if err := ValidSourceRequest(sk.Source); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Add any new sources and kapacitors as specified via server flag
|
||||||
|
if err := h.newSourceKapacitor(ctx, sk.Source, sk.Kapacitor); err != nil {
|
||||||
|
// Continue with server run even if adding NewSource fails
|
||||||
|
h.Logger.
|
||||||
|
WithField("component", "server").
|
||||||
|
WithField("NewSource", "invalid").
|
||||||
|
Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSourceKapacitor adds sources to BoltDB idempotently by name, as well as respective kapacitors
|
||||||
|
func (h *Service) newSourceKapacitor(ctx context.Context, src chronograf.Source, kapa chronograf.Server) error {
|
||||||
|
srcs, err := h.SourcesStore.All(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range srcs {
|
||||||
|
// If source already exists, do nothing
|
||||||
|
if s.Name == src.Name {
|
||||||
|
h.Logger.
|
||||||
|
WithField("component", "server").
|
||||||
|
WithField("NewSource", s.Name).
|
||||||
|
Info("Source already exists")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err = h.SourcesStore.Add(ctx, src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kapa.SrcID = src.ID
|
||||||
|
if _, err := h.ServersStore.Add(ctx, kapa); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
|
"github.com/influxdata/chronograf/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_newSourceResponse(t *testing.T) {
|
func Test_newSourceResponse(t *testing.T) {
|
||||||
|
@ -66,3 +69,180 @@ func Test_newSourceResponse(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestService_newSourceKapacitor(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
ServersStore chronograf.ServersStore
|
||||||
|
Logger chronograf.Logger
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
src chronograf.Source
|
||||||
|
kapa chronograf.Server
|
||||||
|
}
|
||||||
|
srcCount := 0
|
||||||
|
srvCount := 0
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantSrc int
|
||||||
|
wantSrv int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Add when no existing sources",
|
||||||
|
fields: fields{
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
|
||||||
|
return []chronograf.Source{}, nil
|
||||||
|
},
|
||||||
|
AddF: func(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||||
|
srcCount++
|
||||||
|
src.ID = srcCount
|
||||||
|
return src, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServersStore: &mocks.ServersStore{
|
||||||
|
AddF: func(ctx context.Context, srv chronograf.Server) (chronograf.Server, error) {
|
||||||
|
srvCount++
|
||||||
|
return srv, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
src: chronograf.Source{
|
||||||
|
Name: "Influx 1",
|
||||||
|
},
|
||||||
|
kapa: chronograf.Server{
|
||||||
|
Name: "Kapa 1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSrc: 1,
|
||||||
|
wantSrv: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Should not add if existing source",
|
||||||
|
fields: fields{
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
|
||||||
|
return []chronograf.Source{
|
||||||
|
{
|
||||||
|
Name: "Influx 1",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
AddF: func(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||||
|
srcCount++
|
||||||
|
src.ID = srcCount
|
||||||
|
return src, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServersStore: &mocks.ServersStore{
|
||||||
|
AddF: func(ctx context.Context, srv chronograf.Server) (chronograf.Server, error) {
|
||||||
|
srvCount++
|
||||||
|
return srv, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Logger: &mocks.TestLogger{},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
src: chronograf.Source{
|
||||||
|
Name: "Influx 1",
|
||||||
|
},
|
||||||
|
kapa: chronograf.Server{
|
||||||
|
Name: "Kapa 1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSrc: 0,
|
||||||
|
wantSrv: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Error if All returns error",
|
||||||
|
fields: fields{
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
|
||||||
|
return nil, fmt.Errorf("error")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Logger: &mocks.TestLogger{},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Error if Add returns error",
|
||||||
|
fields: fields{
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
|
||||||
|
return []chronograf.Source{}, nil
|
||||||
|
},
|
||||||
|
AddF: func(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{}, fmt.Errorf("error")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Logger: &mocks.TestLogger{},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Error if kapa add is error",
|
||||||
|
fields: fields{
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
|
||||||
|
return []chronograf.Source{}, nil
|
||||||
|
},
|
||||||
|
AddF: func(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||||
|
srcCount++
|
||||||
|
src.ID = srcCount
|
||||||
|
return src, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServersStore: &mocks.ServersStore{
|
||||||
|
AddF: func(ctx context.Context, srv chronograf.Server) (chronograf.Server, error) {
|
||||||
|
srvCount++
|
||||||
|
return chronograf.Server{}, fmt.Errorf("error")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Logger: &mocks.TestLogger{},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
src: chronograf.Source{
|
||||||
|
Name: "Influx 1",
|
||||||
|
},
|
||||||
|
kapa: chronograf.Server{
|
||||||
|
Name: "Kapa 1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSrc: 1,
|
||||||
|
wantSrv: 1,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
srcCount = 0
|
||||||
|
srvCount = 0
|
||||||
|
h := &Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
ServersStore: tt.fields.ServersStore,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
}
|
||||||
|
if err := h.newSourceKapacitor(tt.args.ctx, tt.args.src, tt.args.kapa); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Service.newSourceKapacitor() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
if tt.wantSrc != srcCount {
|
||||||
|
t.Errorf("Service.newSourceKapacitor() count = %d, wantSrc %d", srcCount, tt.wantSrc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue