Add JWT shared secret influxdb auth

Refactor --new-sources to simplify adding shared secrets
pull/10616/head
Chris Goller 2017-07-14 20:02:13 -05:00
parent fa9e118686
commit 8dc08278bd
16 changed files with 4528 additions and 4454 deletions

View File

@ -17,6 +17,7 @@ func MarshalSource(s chronograf.Source) ([]byte, error) {
Type: s.Type,
Username: s.Username,
Password: s.Password,
SharedSecret: s.SharedSecret,
URL: s.URL,
MetaURL: s.MetaURL,
InsecureSkipVerify: s.InsecureSkipVerify,
@ -37,6 +38,7 @@ func UnmarshalSource(data []byte, s *chronograf.Source) error {
s.Type = pb.Type
s.Username = pb.Username
s.Password = pb.Password
s.SharedSecret = pb.SharedSecret
s.URL = pb.URL
s.MetaURL = pb.MetaURL
s.InsecureSkipVerify = pb.InsecureSkipVerify

View File

@ -51,6 +51,7 @@ type Source struct {
Telegraf string `protobuf:"bytes,8,opt,name=Telegraf,proto3" json:"Telegraf,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"`
SharedSecret string `protobuf:"bytes,11,opt,name=SharedSecret,proto3" json:"SharedSecret,omitempty"`
}
func (m *Source) Reset() { *m = Source{} }
@ -293,59 +294,60 @@ func init() {
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
var fileDescriptorInternal = []byte{
// 858 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xdd, 0x6e, 0xe3, 0x44,
0x14, 0xd6, 0xc4, 0x76, 0x62, 0x9f, 0xee, 0x16, 0x34, 0x5a, 0xb1, 0x06, 0x6e, 0x22, 0x0b, 0xa4,
0x82, 0x44, 0x41, 0xec, 0x13, 0xb4, 0xb5, 0x84, 0x42, 0xbb, 0x4b, 0x99, 0xb4, 0xe5, 0x0a, 0xad,
0x26, 0xc9, 0x49, 0x6b, 0xed, 0x24, 0x36, 0x63, 0xbb, 0x59, 0xbf, 0x02, 0x57, 0x3c, 0x01, 0x12,
0x12, 0x57, 0x5c, 0xf2, 0x02, 0x3c, 0x04, 0x2f, 0x84, 0xce, 0xcc, 0xf8, 0x27, 0x6c, 0x41, 0x7b,
0xb5, 0x77, 0xf3, 0x9d, 0x33, 0xf9, 0xe6, 0xfc, 0x7c, 0x9f, 0x03, 0x87, 0xd9, 0xb6, 0x42, 0xbd,
0x95, 0xea, 0xb8, 0xd0, 0x79, 0x95, 0xf3, 0xb0, 0xc5, 0xc9, 0xcf, 0x23, 0x18, 0xcf, 0xf3, 0x5a,
0x2f, 0x91, 0x1f, 0xc2, 0x68, 0x96, 0xc6, 0x6c, 0xca, 0x8e, 0x3c, 0x31, 0x9a, 0xa5, 0x9c, 0x83,
0xff, 0x42, 0x6e, 0x30, 0x1e, 0x4d, 0xd9, 0x51, 0x24, 0xcc, 0x99, 0x62, 0x57, 0x4d, 0x81, 0xb1,
0x67, 0x63, 0x74, 0xe6, 0x1f, 0x41, 0x78, 0x5d, 0x12, 0xdb, 0x06, 0x63, 0xdf, 0xc4, 0x3b, 0x4c,
0xb9, 0x4b, 0x59, 0x96, 0xbb, 0x5c, 0xaf, 0xe2, 0xc0, 0xe6, 0x5a, 0xcc, 0xdf, 0x07, 0xef, 0x5a,
0x5c, 0xc4, 0x63, 0x13, 0xa6, 0x23, 0x8f, 0x61, 0x92, 0xe2, 0x5a, 0xd6, 0xaa, 0x8a, 0x27, 0x53,
0x76, 0x14, 0x8a, 0x16, 0x12, 0xcf, 0x15, 0x2a, 0xbc, 0xd5, 0x72, 0x1d, 0x87, 0x96, 0xa7, 0xc5,
0xfc, 0x18, 0xf8, 0x6c, 0x5b, 0xe2, 0xb2, 0xd6, 0x38, 0x7f, 0x95, 0x15, 0x37, 0xa8, 0xb3, 0x75,
0x13, 0x47, 0x86, 0xe0, 0x81, 0x0c, 0xbd, 0xf2, 0x1c, 0x2b, 0x49, 0x6f, 0x83, 0xa1, 0x6a, 0x61,
0xf2, 0x0b, 0x83, 0x28, 0x95, 0xe5, 0xdd, 0x22, 0x97, 0x7a, 0xf5, 0x56, 0xf3, 0xf8, 0x02, 0x82,
0x25, 0x2a, 0x55, 0xc6, 0xde, 0xd4, 0x3b, 0x3a, 0xf8, 0xfa, 0xe9, 0x71, 0x37, 0xe8, 0x8e, 0xe7,
0x0c, 0x95, 0x12, 0xf6, 0x16, 0xff, 0x0a, 0xa2, 0x0a, 0x37, 0x85, 0x92, 0x15, 0x96, 0xb1, 0x6f,
0x7e, 0xc2, 0xfb, 0x9f, 0x5c, 0xb9, 0x94, 0xe8, 0x2f, 0x25, 0x7f, 0x30, 0x78, 0xbc, 0x47, 0xc5,
0x1f, 0x01, 0x7b, 0x6d, 0xaa, 0x0a, 0x04, 0x7b, 0x4d, 0xa8, 0x31, 0x15, 0x05, 0x82, 0x35, 0x84,
0x76, 0x66, 0x37, 0x81, 0x60, 0x3b, 0x42, 0x77, 0x66, 0x23, 0x81, 0x60, 0x77, 0xfc, 0x33, 0x98,
0xfc, 0x54, 0xa3, 0xce, 0xb0, 0x8c, 0x03, 0xf3, 0xf2, 0x7b, 0xfd, 0xcb, 0xdf, 0xd7, 0xa8, 0x1b,
0xd1, 0xe6, 0xa9, 0x53, 0xb3, 0x4d, 0xbb, 0x1a, 0x73, 0xa6, 0x58, 0x45, 0x9b, 0x9f, 0xd8, 0x18,
0x9d, 0xdd, 0x84, 0xec, 0x3e, 0x46, 0xb3, 0x34, 0xf9, 0x8b, 0xd1, 0x9a, 0x6c, 0xe9, 0x83, 0xf1,
0x99, 0x24, 0xff, 0x10, 0x42, 0x6a, 0xeb, 0xe5, 0xbd, 0xd4, 0x6e, 0x84, 0x13, 0xc2, 0x37, 0x52,
0xf3, 0x2f, 0x61, 0x7c, 0x2f, 0x55, 0x8d, 0x0f, 0x8c, 0xb1, 0xa5, 0xbb, 0xa1, 0xbc, 0x70, 0xd7,
0xba, 0x62, 0xfc, 0x41, 0x31, 0x4f, 0x20, 0x50, 0x72, 0x81, 0xca, 0xe9, 0xcc, 0x02, 0x5a, 0x10,
0x75, 0xd5, 0x98, 0x5e, 0x1e, 0x64, 0xb6, 0xbd, 0xdb, 0x5b, 0xc9, 0x35, 0x3c, 0xde, 0x7b, 0xb1,
0x7b, 0x89, 0xed, 0xbf, 0x64, 0xea, 0x70, 0x6d, 0x58, 0x40, 0x12, 0x2d, 0x51, 0xe1, 0xb2, 0xc2,
0x95, 0x59, 0x41, 0x28, 0x3a, 0x9c, 0xfc, 0xc6, 0x7a, 0x5e, 0xf3, 0x1e, 0x89, 0x70, 0x99, 0x6f,
0x36, 0x72, 0xbb, 0x72, 0xd4, 0x2d, 0xa4, 0xb9, 0xad, 0x16, 0x8e, 0x7a, 0xb4, 0x5a, 0x10, 0xd6,
0x85, 0x33, 0xdc, 0x48, 0x17, 0x7c, 0x0a, 0x07, 0x1b, 0x94, 0x65, 0xad, 0x71, 0x83, 0xdb, 0xca,
0x8d, 0x60, 0x18, 0xe2, 0x4f, 0x61, 0x52, 0xc9, 0xdb, 0x97, 0xaf, 0xb0, 0x71, 0xb3, 0x18, 0x57,
0xf2, 0xf6, 0x1c, 0x1b, 0xfe, 0x31, 0x44, 0xeb, 0x0c, 0xd5, 0xca, 0xa4, 0xec, 0x72, 0x43, 0x13,
0x38, 0xc7, 0x26, 0xf9, 0x9d, 0xc1, 0x78, 0x8e, 0xfa, 0x1e, 0xf5, 0x5b, 0x29, 0x7f, 0xe8, 0x7a,
0xef, 0x7f, 0x5c, 0xef, 0x3f, 0xec, 0xfa, 0xa0, 0x77, 0xfd, 0x13, 0x08, 0xe6, 0x7a, 0x39, 0x4b,
0x4d, 0x45, 0x9e, 0xb0, 0x80, 0x7f, 0x00, 0xe3, 0x93, 0x65, 0x95, 0xdd, 0xa3, 0xfb, 0x14, 0x38,
0x94, 0xfc, 0xca, 0x60, 0x7c, 0x21, 0x9b, 0xbc, 0xae, 0xde, 0x50, 0xd8, 0x14, 0x0e, 0x4e, 0x8a,
0x42, 0x65, 0x4b, 0x59, 0x65, 0xf9, 0xd6, 0x55, 0x3b, 0x0c, 0xd1, 0x8d, 0xe7, 0x83, 0xd9, 0xd9,
0xba, 0x87, 0x21, 0xfe, 0x09, 0x04, 0x67, 0xc6, 0xd0, 0xd6, 0x9d, 0x87, 0xbd, 0x5e, 0xac, 0x8f,
0x4d, 0x92, 0x1a, 0x3c, 0xa9, 0xab, 0x7c, 0xad, 0xf2, 0x9d, 0xe9, 0x24, 0x14, 0x1d, 0x4e, 0xfe,
0x66, 0xe0, 0xbf, 0x2b, 0xa3, 0x3e, 0x02, 0x96, 0xb9, 0x45, 0xb2, 0xac, 0xb3, 0xed, 0x64, 0x60,
0xdb, 0x18, 0x26, 0x8d, 0x96, 0xdb, 0x5b, 0x2c, 0xe3, 0x70, 0xea, 0x1d, 0x79, 0xa2, 0x85, 0x26,
0x63, 0x3c, 0x52, 0xc6, 0xd1, 0xd4, 0x23, 0x05, 0x3a, 0xd8, 0x69, 0x1e, 0x7a, 0xcd, 0x27, 0x7f,
0x32, 0x08, 0x3a, 0xe5, 0x9e, 0xed, 0x2b, 0xf7, 0xac, 0x57, 0x6e, 0x7a, 0xda, 0x2a, 0x37, 0x3d,
0x25, 0x2c, 0x2e, 0x5b, 0xe5, 0x8a, 0x4b, 0x9a, 0xda, 0x37, 0x3a, 0xaf, 0x8b, 0xd3, 0xc6, 0x8e,
0x37, 0x12, 0x1d, 0xa6, 0x75, 0xff, 0x70, 0x87, 0xda, 0xf5, 0x1c, 0x09, 0x87, 0x48, 0x1c, 0x17,
0xc6, 0xd5, 0xb6, 0x4b, 0x0b, 0xf8, 0xa7, 0x10, 0x08, 0xea, 0xc2, 0xb4, 0xba, 0x37, 0x20, 0x13,
0x16, 0x36, 0x9b, 0x3c, 0x73, 0xd7, 0x88, 0xe5, 0xba, 0x28, 0x50, 0x3b, 0x4d, 0x5b, 0x60, 0xb8,
0xf3, 0x1d, 0xda, 0xcf, 0x91, 0x27, 0x2c, 0x48, 0x7e, 0x84, 0xe8, 0x44, 0xa1, 0xae, 0x44, 0xad,
0xde, 0xfc, 0x88, 0x71, 0xf0, 0xbf, 0x9d, 0x7f, 0xf7, 0xa2, 0x75, 0x02, 0x9d, 0x7b, 0xfd, 0x7a,
0xff, 0xd2, 0xef, 0xb9, 0x2c, 0xe4, 0x2c, 0x35, 0x8b, 0xf5, 0x84, 0x43, 0xc9, 0xe7, 0xe0, 0x93,
0x4f, 0x06, 0xcc, 0xfe, 0x7f, 0x79, 0x6c, 0x31, 0x36, 0xff, 0xd6, 0xcf, 0xfe, 0x09, 0x00, 0x00,
0xff, 0xff, 0xa7, 0xc6, 0x53, 0x22, 0xbf, 0x07, 0x00, 0x00,
// 876 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x55, 0xdf, 0x6e, 0xe3, 0xc4,
0x17, 0xd6, 0xc4, 0x76, 0x62, 0x9f, 0x76, 0xfb, 0xfb, 0x69, 0xb4, 0x62, 0x0d, 0xdc, 0x44, 0x16,
0x48, 0x01, 0x89, 0x82, 0xd8, 0x27, 0x68, 0x6b, 0x09, 0x85, 0x76, 0x97, 0x32, 0x69, 0xcb, 0x15,
0x5a, 0x4d, 0x9c, 0x93, 0xc6, 0x5a, 0x27, 0x36, 0x63, 0xbb, 0x59, 0xbf, 0x05, 0x4f, 0x80, 0x84,
0xc4, 0x15, 0x17, 0x5c, 0xf0, 0x02, 0x3c, 0x04, 0x2f, 0x84, 0xce, 0xcc, 0xf8, 0x4f, 0xd8, 0x82,
0xf6, 0x8a, 0xbb, 0xf9, 0xce, 0x19, 0x7f, 0xe7, 0xdf, 0x77, 0xc6, 0x70, 0x92, 0xee, 0x2a, 0x54,
0x3b, 0x99, 0x9d, 0x16, 0x2a, 0xaf, 0x72, 0xee, 0xb7, 0x38, 0xfa, 0x6d, 0x04, 0xe3, 0x45, 0x5e,
0xab, 0x04, 0xf9, 0x09, 0x8c, 0xe6, 0x71, 0xc8, 0xa6, 0x6c, 0xe6, 0x88, 0xd1, 0x3c, 0xe6, 0x1c,
0xdc, 0x97, 0x72, 0x8b, 0xe1, 0x68, 0xca, 0x66, 0x81, 0xd0, 0x67, 0xb2, 0xdd, 0x34, 0x05, 0x86,
0x8e, 0xb1, 0xd1, 0x99, 0x7f, 0x00, 0xfe, 0x6d, 0x49, 0x6c, 0x5b, 0x0c, 0x5d, 0x6d, 0xef, 0x30,
0xf9, 0xae, 0x65, 0x59, 0xee, 0x73, 0xb5, 0x0a, 0x3d, 0xe3, 0x6b, 0x31, 0xff, 0x3f, 0x38, 0xb7,
0xe2, 0x2a, 0x1c, 0x6b, 0x33, 0x1d, 0x79, 0x08, 0x93, 0x18, 0xd7, 0xb2, 0xce, 0xaa, 0x70, 0x32,
0x65, 0x33, 0x5f, 0xb4, 0x90, 0x78, 0x6e, 0x30, 0xc3, 0x7b, 0x25, 0xd7, 0xa1, 0x6f, 0x78, 0x5a,
0xcc, 0x4f, 0x81, 0xcf, 0x77, 0x25, 0x26, 0xb5, 0xc2, 0xc5, 0xeb, 0xb4, 0xb8, 0x43, 0x95, 0xae,
0x9b, 0x30, 0xd0, 0x04, 0x8f, 0x78, 0x28, 0xca, 0x0b, 0xac, 0x24, 0xc5, 0x06, 0x4d, 0xd5, 0x42,
0x1e, 0xc1, 0xf1, 0x62, 0x23, 0x15, 0xae, 0x16, 0x98, 0x28, 0xac, 0xc2, 0x23, 0xed, 0x3e, 0xb0,
0x45, 0x3f, 0x32, 0x08, 0x62, 0x59, 0x6e, 0x96, 0xb9, 0x54, 0xab, 0x77, 0xea, 0xd9, 0x67, 0xe0,
0x25, 0x98, 0x65, 0x65, 0xe8, 0x4c, 0x9d, 0xd9, 0xd1, 0x97, 0xcf, 0x4e, 0xbb, 0x61, 0x74, 0x3c,
0x17, 0x98, 0x65, 0xc2, 0xdc, 0xe2, 0x5f, 0x40, 0x50, 0xe1, 0xb6, 0xc8, 0x64, 0x85, 0x65, 0xe8,
0xea, 0x4f, 0x78, 0xff, 0xc9, 0x8d, 0x75, 0x89, 0xfe, 0x52, 0xf4, 0x2b, 0x83, 0x27, 0x07, 0x54,
0xfc, 0x18, 0xd8, 0x1b, 0x9d, 0x95, 0x27, 0xd8, 0x1b, 0x42, 0x8d, 0xce, 0xc8, 0x13, 0xac, 0x21,
0xb4, 0xd7, 0xf3, 0xf3, 0x04, 0xdb, 0x13, 0xda, 0xe8, 0xa9, 0x79, 0x82, 0x6d, 0xf8, 0x27, 0x30,
0xf9, 0xa1, 0x46, 0x95, 0x62, 0x19, 0x7a, 0x3a, 0xf2, 0xff, 0xfa, 0xc8, 0xdf, 0xd6, 0xa8, 0x1a,
0xd1, 0xfa, 0xa9, 0x52, 0x3d, 0x71, 0x33, 0x3e, 0x7d, 0x26, 0x5b, 0x45, 0xea, 0x98, 0x18, 0x1b,
0x9d, 0x6d, 0x87, 0xcc, 0xcc, 0x46, 0xf3, 0x38, 0xfa, 0x83, 0xd1, 0x28, 0x4d, 0xea, 0x83, 0xf6,
0x69, 0x27, 0x7f, 0x1f, 0x7c, 0x2a, 0xeb, 0xd5, 0x83, 0x54, 0xb6, 0x85, 0x13, 0xc2, 0x77, 0x52,
0xf1, 0xcf, 0x61, 0xfc, 0x20, 0xb3, 0x1a, 0x1f, 0x69, 0x63, 0x4b, 0x77, 0x47, 0x7e, 0x61, 0xaf,
0x75, 0xc9, 0xb8, 0x83, 0x64, 0x9e, 0x82, 0x97, 0xc9, 0x25, 0x66, 0x56, 0x8b, 0x06, 0xd0, 0x80,
0xa8, 0xaa, 0x46, 0xd7, 0xf2, 0x28, 0xb3, 0xa9, 0xdd, 0xdc, 0x8a, 0x6e, 0xe1, 0xc9, 0x41, 0xc4,
0x2e, 0x12, 0x3b, 0x8c, 0xa4, 0xf3, 0xb0, 0x65, 0x18, 0x40, 0x32, 0x2e, 0x31, 0xc3, 0xa4, 0xc2,
0x95, 0x1e, 0x81, 0x2f, 0x3a, 0x1c, 0xfd, 0xcc, 0x7a, 0x5e, 0x1d, 0x8f, 0x84, 0x9a, 0xe4, 0xdb,
0xad, 0xdc, 0xad, 0x2c, 0x75, 0x0b, 0xa9, 0x6f, 0xab, 0xa5, 0xa5, 0x1e, 0xad, 0x96, 0x84, 0x55,
0x61, 0x97, 0x72, 0xa4, 0x0a, 0x3e, 0x85, 0xa3, 0x2d, 0xca, 0xb2, 0x56, 0xb8, 0xc5, 0x5d, 0x65,
0x5b, 0x30, 0x34, 0xf1, 0x67, 0x30, 0xa9, 0xe4, 0xfd, 0xab, 0xd7, 0xd8, 0xd8, 0x5e, 0x8c, 0x2b,
0x79, 0x7f, 0x89, 0x0d, 0xff, 0x10, 0x82, 0x75, 0x8a, 0xd9, 0x4a, 0xbb, 0xcc, 0x70, 0x7d, 0x6d,
0xb8, 0xc4, 0x26, 0xfa, 0x85, 0xc1, 0x78, 0x81, 0xea, 0x01, 0xd5, 0x3b, 0x29, 0x7f, 0xf8, 0x32,
0x38, 0xff, 0xf2, 0x32, 0xb8, 0x8f, 0xbf, 0x0c, 0x5e, 0xff, 0x32, 0x3c, 0x05, 0x6f, 0xa1, 0x92,
0x79, 0xac, 0x33, 0x72, 0x84, 0x01, 0xfc, 0x3d, 0x18, 0x9f, 0x25, 0x55, 0xfa, 0x80, 0xf6, 0xb9,
0xb0, 0x28, 0xfa, 0x89, 0xc1, 0xf8, 0x4a, 0x36, 0x79, 0x5d, 0xbd, 0xa5, 0xb0, 0x29, 0x1c, 0x9d,
0x15, 0x45, 0x96, 0x26, 0xb2, 0x4a, 0xf3, 0x9d, 0xcd, 0x76, 0x68, 0xa2, 0x1b, 0x2f, 0x06, 0xbd,
0x33, 0x79, 0x0f, 0x4d, 0xfc, 0x23, 0xf0, 0x2e, 0xf4, 0x42, 0x9b, 0xed, 0x3c, 0xe9, 0xf5, 0x62,
0xf6, 0x58, 0x3b, 0xa9, 0xc0, 0xb3, 0xba, 0xca, 0xd7, 0x59, 0xbe, 0xd7, 0x95, 0xf8, 0xa2, 0xc3,
0xd1, 0x9f, 0x0c, 0xdc, 0xff, 0x6a, 0x51, 0x8f, 0x81, 0xa5, 0x76, 0x90, 0x2c, 0xed, 0xd6, 0x76,
0x32, 0x58, 0xdb, 0x10, 0x26, 0x8d, 0x92, 0xbb, 0x7b, 0x2c, 0x43, 0x7f, 0xea, 0xcc, 0x1c, 0xd1,
0x42, 0xed, 0xd1, 0x3b, 0x52, 0x86, 0xc1, 0xd4, 0x21, 0x05, 0x5a, 0xd8, 0x69, 0x1e, 0x7a, 0xcd,
0x47, 0xbf, 0x33, 0xf0, 0x3a, 0xe5, 0x5e, 0x1c, 0x2a, 0xf7, 0xa2, 0x57, 0x6e, 0x7c, 0xde, 0x2a,
0x37, 0x3e, 0x27, 0x2c, 0xae, 0x5b, 0xe5, 0x8a, 0x6b, 0xea, 0xda, 0x57, 0x2a, 0xaf, 0x8b, 0xf3,
0xc6, 0xb4, 0x37, 0x10, 0x1d, 0xa6, 0x71, 0x7f, 0xb7, 0x41, 0x65, 0x6b, 0x0e, 0x84, 0x45, 0x24,
0x8e, 0x2b, 0xbd, 0xd5, 0xa6, 0x4a, 0x03, 0xf8, 0xc7, 0xe0, 0x09, 0xaa, 0x42, 0x97, 0x7a, 0xd0,
0x20, 0x6d, 0x16, 0xc6, 0x1b, 0x3d, 0xb7, 0xd7, 0x88, 0xe5, 0xb6, 0x28, 0x50, 0x59, 0x4d, 0x1b,
0xa0, 0xb9, 0xf3, 0x3d, 0x9a, 0xe7, 0xc8, 0x11, 0x06, 0x44, 0xdf, 0x43, 0x70, 0x96, 0xa1, 0xaa,
0x44, 0x9d, 0xbd, 0xfd, 0x88, 0x71, 0x70, 0xbf, 0x5e, 0x7c, 0xf3, 0xb2, 0xdd, 0x04, 0x3a, 0xf7,
0xfa, 0x75, 0xfe, 0xa6, 0xdf, 0x4b, 0x59, 0xc8, 0x79, 0xac, 0x07, 0xeb, 0x08, 0x8b, 0xa2, 0x4f,
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,
}

View File

@ -12,6 +12,7 @@ message Source {
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
string MetaURL = 10; // MetaURL is the connection URL for the meta node.
string SharedSecret = 11; // SharedSecret signs the optional InfluxDB JWT Authorization
}
message Dashboard {

View File

@ -40,6 +40,38 @@ func TestMarshalSource(t *testing.T) {
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) {
v := chronograf.Server{

View File

@ -346,6 +346,7 @@ type Source struct {
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
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
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.
@ -625,44 +626,3 @@ type LayoutStore interface {
// Update the dashboard in the store.
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
}

View File

@ -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")
}
}

View File

@ -120,14 +120,18 @@ func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
c.dataNodes = ring.New(len(cluster.DataNodes))
for _, dn := range cluster.DataNodes {
cl, err := influx.NewClient(dn.HTTPAddr, c.Logger)
if err != nil {
cl := &influx.Client{
Logger: c.Logger,
}
dataSrc := &chronograf.Source{}
*dataSrc = *src
dataSrc.URL = dn.HTTPAddr
if err := cl.Connect(ctx, dataSrc); err != nil {
continue
} else {
}
c.dataNodes.Value = cl
c.dataNodes = c.dataNodes.Next()
}
}
return nil
}

View File

@ -28,27 +28,11 @@ var (
// Client is a device for retrieving time series data from an InfluxDB instance
type Client struct {
URL *url.URL
Bearer Bearer
InsecureSkipVerify bool
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
// to check for some errors
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
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{}
if c.InsecureSkipVerify {
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 {
u, err := url.Parse(src.URL)
if err != nil {
@ -169,6 +162,16 @@ func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
c.InsecureSkipVerify = src.InsecureSkipVerify
}
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
}

View File

@ -2,16 +2,34 @@ package influx_test
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
gojwt "github.com/dgrijalva/jwt-go"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/influx"
"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) {
t.Parallel()
called := false
@ -26,7 +44,7 @@ func Test_Influx_MakesRequestsToQueryEndpoint(t *testing.T) {
defer ts.Close()
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 {
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) {
called := false
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()
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 {
t.Fatal("Unexpected error initializing client: err:", err)
}
@ -97,7 +235,7 @@ func Test_Influx_HTTPS_InsecureSkipVerify(t *testing.T) {
ctx := context.Background()
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 {
t.Fatal("Unexpected error initializing client: err:", err)
}
@ -166,7 +304,7 @@ func Test_Influx_CancelsInFlightRequests(t *testing.T) {
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())
errs := make(chan (error))
@ -209,7 +347,7 @@ func Test_Influx_CancelsInFlightRequests(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 {
t.Fatal("Expected err but was nil")
}
@ -221,7 +359,7 @@ func Test_Influx_ReportsInfluxErrs(t *testing.T) {
}))
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 {
t.Fatal("Encountered unexpected error while initializing influx client: err:", err)
}

41
influx/jwt.go Normal file
View File

@ -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))
}

44
influx/jwt_test.go Normal file
View File

@ -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)
}
})
}
}

View File

@ -3,7 +3,6 @@ package server
import (
"context"
"crypto/tls"
"encoding/json"
"log"
"math/rand"
"net"
@ -51,7 +50,7 @@ type Server struct {
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"`
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."`
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
}
service := openService(ctx, s.BoltPath, layoutBuilder, sourcesBuilder, kapacitorBuilder, logger, s.useAuth())
go processNewSources(ctx, service, s.NewSources, logger)
if err := service.HandleNewSources(ctx, s.NewSources); err != nil {
logger.
WithField("component", "server").
WithField("new-sources", "invalid").
Error(err)
return err
}
basepath = s.Basepath
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.
func reportUsageStats(bi BuildInfo, logger chronograf.Logger) {
rand.Seed(time.Now().UTC().UnixNano())

View File

@ -43,18 +43,15 @@ type InfluxClient struct{}
// New creates a client to connect to OSS or enterprise
func (c *InfluxClient) New(src chronograf.Source, logger chronograf.Logger) (chronograf.TimeSeries, error) {
if src.Type == chronograf.InfluxEnterprise && src.MetaURL != "" {
dataNode := &influx.Client{
client := &influx.Client{
Logger: logger,
}
if err := dataNode.Connect(context.TODO(), &src); err != nil {
if err := client.Connect(context.TODO(), &src); err != nil {
return nil, err
}
if src.Type == chronograf.InfluxEnterprise && src.MetaURL != "" {
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{
Logger: logger,
}, nil
return client, nil
}

View File

@ -34,8 +34,9 @@ func newSourceResponse(src chronograf.Source) sourceResponse {
src.Telegraf = "telegraf"
}
// Omit the password on response
// Omit the password and shared secret on response
src.Password = ""
src.SharedSecret = ""
httpAPISrcs := "/chronograf/v1/sources"
res := sourceResponse{
@ -99,6 +100,7 @@ func (h *Service) tsdbType(ctx context.Context, src *chronograf.Source) (string,
cli := &influx.Client{
Logger: h.Logger,
}
if err := cli.Connect(ctx, src); err != nil {
return "", err
}
@ -293,3 +295,69 @@ func ValidSourceRequest(s chronograf.Source) error {
}
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
}

View File

@ -1,10 +1,13 @@
package server
import (
"context"
"fmt"
"reflect"
"testing"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/mocks"
)
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