feat: add rocketchat notifier (#3600)
* feat: add rocketchat notifier Signed-off-by: Christoph Maser <christoph.maser+github@gmail.com> Co-authored-by: George Robinson <george.robinson@grafana.com> * Update notify/rocketchat/rocketchat.go Co-authored-by: George Robinson <george.robinson@grafana.com> Signed-off-by: gotjosh <josue.abreu@gmail.com> --------- Signed-off-by: Christoph Maser <christoph.maser+github@gmail.com> Signed-off-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: George Robinson <george.robinson@grafana.com> Co-authored-by: gotjosh <josue.abreu@gmail.com>
This commit is contained in:
parent
e6cb11ce4d
commit
8572fe849c
|
@ -163,9 +163,9 @@ var Assets = func() http.FileSystem {
|
||||||
"/templates/default.tmpl": &vfsgen۰CompressedFileInfo{
|
"/templates/default.tmpl": &vfsgen۰CompressedFileInfo{
|
||||||
name: "default.tmpl",
|
name: "default.tmpl",
|
||||||
modTime: time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
|
modTime: time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
|
||||||
uncompressedSize: 7656,
|
uncompressedSize: 8053,
|
||||||
|
|
||||||
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\x59\x4d\x6f\xe3\x36\x10\xbd\xfb\x57\x0c\xb4\x3d\xc4\x87\x68\x8b\x1e\x03\x04\xc5\xa2\xe8\xc7\x21\x2d\x0a\x2f\xd2\x4b\x51\x08\x8c\x34\x56\x98\x50\xa4\x42\x8e\xec\x18\x8e\xfe\x7b\x41\x49\x96\xa9\x0f\xdb\x94\xd7\x3d\xd5\xb7\x98\x9a\x79\x33\x7c\x6f\x34\x43\x2a\xdb\x2d\x24\xb8\xe4\x12\x21\x88\x22\x26\x50\x53\xc6\x24\x4b\x51\x07\x50\x96\x5f\x9c\xdf\xdb\x2d\xa0\x4c\xa0\x2c\x67\x07\x5d\x1e\x17\x0f\xd6\x6b\xbb\x85\xf0\xe7\x77\x42\x2d\x99\x78\x5c\x3c\x40\x59\x7e\xfe\xf4\xb9\xb2\x33\x3f\x6a\x8c\x91\xaf\x50\xdf\x5b\xa3\x45\xf3\x03\x3e\xa0\xd0\xe2\xad\x40\xbd\xa9\xdd\x9b\x40\xdd\x48\xa6\x78\x7a\xc1\x98\x6c\x84\xbf\xad\xf7\x57\x62\x54\x18\xf8\x00\x52\x8f\x79\x8e\xba\x76\xe5\x4b\xc0\xb7\xf6\x61\xb0\xe4\x9a\xcb\xd4\xfa\xdc\x59\x9f\x6a\x43\x26\xfc\xa5\x5a\x85\x0f\x10\x28\xdd\x88\xff\x80\x35\xfa\x55\xab\x22\x7f\x60\x4f\x28\x4c\xf8\x55\x69\xc2\xe4\x4f\xc6\xb5\x09\xff\x62\xa2\x40\x1b\xf0\x45\x71\x09\x01\x58\x54\xa8\x43\xa6\x04\x37\x16\x2b\xfc\x49\x65\x99\x92\xb5\xf3\xbc\x59\x73\xf0\xe6\x50\x96\x37\xdb\x2d\xac\x39\x3d\x77\x8d\xc3\x05\x66\x6a\x85\xdd\xe8\x7f\xb0\x0c\x4d\xc3\xe8\x58\xf4\x36\xf1\x79\xfb\xd7\x01\x99\x12\x34\xb1\xe6\x39\x71\x25\x83\x23\x1c\x13\xbe\x53\x2d\x69\x24\xb8\xa1\xc6\x54\x33\x99\x22\x84\x50\x96\x75\x5e\x77\xb3\xfd\xe2\x90\x27\xcb\xca\x6d\x45\xa4\x4d\xdf\xfe\xba\x87\x76\x03\x4d\x62\x75\xf0\x2f\x52\x2a\x62\x36\xa7\x0e\xa4\xb3\x7c\x1e\xee\x57\x55\xe8\x18\xef\x6a\x31\x51\xa2\x66\xa4\x74\x5d\x89\xb3\x11\xa2\x8e\x52\x10\x65\x4c\xbf\x26\x6a\x2d\x07\x5c\xcc\x7c\xc9\xf0\xcc\x7a\x36\x9d\x0e\x5f\x64\x2f\x42\x66\xe3\x8c\x18\xc1\xe2\xd7\x30\xc1\x25\x2b\x04\x85\xc4\x49\x60\x43\x05\x61\x96\x0b\x46\xdd\x97\x33\x3c\x54\x83\x5d\x9c\xc2\xd8\xf6\x90\x8d\x41\x75\x9b\x90\x27\xde\x92\x09\xf1\xc4\xe2\xd7\x01\xde\x68\xfa\x16\x14\x3e\xe0\x94\xa1\xe0\xf2\xd5\x3b\x83\xb8\xc9\x80\x27\x81\x9f\x43\xae\xd1\xd6\x9a\xa7\xb5\x93\xd0\x51\xc6\xaa\x1e\xec\x99\x32\x8f\x95\xc4\x4c\xbd\xf0\xc0\xdf\xbe\xd0\xc2\x37\x63\xff\xcd\x2d\x95\xa2\x7a\xe2\x38\x35\xe8\x9a\xe7\x76\x6b\x49\x41\x9b\xd6\x65\xd8\xd0\xa6\x95\xe3\x10\x31\x16\x1c\x25\x9d\x5f\x90\x87\x10\xf7\x53\xf1\x3c\xcd\x86\xb8\x5c\x1a\x62\x32\x46\x33\x82\x3b\xe8\xe0\xe1\x61\x56\x55\x6e\x52\x94\x1c\x5b\xe0\x0c\x8d\x61\xe9\x79\xef\xf7\x00\x6c\xa8\x50\x33\xf0\x0e\x34\xb4\xd1\x09\x37\xeb\xcd\xd7\xce\x00\x9f\xc3\xf7\x70\x6b\x1b\x67\xb5\x08\xf5\x62\xd5\x3a\x8f\x33\xd2\x3d\x05\x54\x41\x6e\x9d\x1d\x8d\xc4\x5b\xa0\x51\x62\x85\x49\x2f\xe2\x6e\xd9\x3f\xe6\xce\x63\x10\xf5\xd6\x87\x52\x53\xf5\xf1\xe9\xd5\xd4\x51\x7d\x8d\xf1\x33\xa3\xa9\x9a\xcf\xae\xfa\x1d\xd1\xcf\x3d\x28\x3f\x6a\x31\xc0\x1b\xd5\xe7\x80\xea\x3d\x7d\x48\x45\x76\x58\x1e\xec\xa4\x43\xf3\x9c\x69\xda\x4c\xb0\x27\x96\xfa\x5a\xb3\x14\x25\x45\xfd\x11\xd7\xad\xaf\x15\x8f\x49\x69\x95\x9b\x7d\xd9\x12\x23\x8c\xba\x85\x76\xad\xa5\x69\xbd\x60\xc8\x2a\x4a\xe2\xb4\x89\x12\x6e\x72\xc1\x36\xd1\x81\xd3\xd4\xe9\xc6\x3d\x44\xce\x94\xe4\xa4\x2c\x21\x11\x29\x25\x26\x8e\xc4\xce\xec\x2a\xcc\xb3\x5a\xa1\xbe\xc0\xf9\x71\x00\xf5\xdf\xd7\xd3\x65\xca\xc9\xbf\x9a\x2e\x57\x4c\xc3\x23\xfd\x31\x26\xf7\x67\xba\x29\x33\xc5\x3d\xcd\x49\xe7\x65\xdf\x5f\xd3\xa7\xdf\x11\x1c\x9c\xab\xbc\x53\xe4\x75\x59\x24\x14\x98\x6a\x96\x8d\x51\xf9\xbf\x25\x25\xe1\x26\x56\x3a\xb9\x40\x23\xea\x23\x5d\xd9\xb5\xc7\x84\x27\x7c\xbf\xbe\xba\xdf\xcc\x63\x66\x08\x59\xe6\x36\xd3\x2c\x63\x7a\x73\x56\x9d\xf6\xb1\xce\xaf\xf8\x01\x52\x73\xb3\xf7\x91\xe9\x13\x4c\x12\xca\xf9\xdc\xf6\xcd\x8a\xb5\xa1\x7d\x35\x1b\x09\x7e\x86\x78\xab\x1f\x2e\x47\xb9\x8b\x75\x25\x7d\x8c\xf4\x17\xae\xd9\x45\x5e\x97\x0e\x50\xef\xdb\xc5\x95\xf3\x59\x75\x2d\x19\xe5\x2a\xd7\x5c\x69\x6e\x6f\x9c\xb7\xcd\xed\xe5\xbb\xdd\x12\xdc\xdd\x43\x10\xec\x2e\x35\xbb\xef\xd9\x9d\xdd\x5a\x1f\x00\x80\xca\xcf\xe0\x0a\x77\x7e\x5c\x26\xf8\xbe\xfb\xa4\x0e\xc1\xee\x51\xd0\xf1\xe0\x4b\xb8\xc1\x37\xc7\x31\x88\x35\x27\x1e\x33\x11\xcc\x5b\xc3\x16\xbe\x4d\xeb\x1e\x82\xdf\x78\xfa\xdc\xc5\x42\x61\xb0\x02\x64\x32\xe9\xa3\xae\x99\x96\x5c\xa6\xc1\x1c\x6e\x24\x3a\x40\x35\xcc\xfc\x44\xac\xdf\x31\xe1\x45\xe6\x1f\x8d\xcb\xa5\xb2\xa1\xec\xea\x3e\xd4\xc9\x30\x0f\x6a\xdd\x8b\x21\x93\x56\x13\xf7\xef\xfa\x7f\x64\x2e\x74\xc7\xad\xab\x53\x5b\x18\x83\xd8\x93\xd4\x9a\xac\x98\x87\x6a\x17\x57\xce\x4b\xbd\xcb\x29\x78\x5a\xc5\xbe\x92\xa7\x94\xdd\x23\xf5\x9f\xfe\x1b\x00\x00\xff\xff\x7a\xa6\xa9\x68\xe8\x1d\x00\x00"),
|
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\x59\xcf\x6f\xeb\x36\x0c\xbe\xe7\xaf\x20\xfc\x76\x68\x0e\xf5\x1b\x76\x2c\x50\x0c\x0f\xc3\x7e\x1c\xba\x61\x68\xd1\x5d\x86\x21\x50\x6d\xc6\x55\x2b\x4b\xae\x44\x27\x0d\xd2\xfc\xef\x83\x6c\xc7\x91\x6c\x27\x91\xd3\xec\xb4\xdc\x12\x99\xfc\x48\x7f\x1f\x4d\x4a\xf6\x7a\x0d\x29\xce\xb9\x44\x88\x66\x33\x26\x50\x53\xce\x24\xcb\x50\x47\xb0\xd9\x7c\x73\xfe\xaf\xd7\x80\x32\x85\xcd\x66\xb2\xd7\xe5\xf1\xfe\xce\x7a\xad\xd7\x10\xff\xfc\x4e\xa8\x25\x13\x8f\xf7\x77\xb0\xd9\x7c\xfd\xf2\xb5\xb2\x33\x3f\x6a\x4c\x90\x2f\x50\xdf\x5a\xa3\xfb\xe6\x0f\x7c\x40\xa9\xc5\x5b\x89\x7a\x55\xbb\x37\x81\xfc\x48\xa6\x7c\x7a\xc1\x84\x6c\x84\xbf\xad\xf7\x03\x31\x2a\x0d\x7c\x00\xa9\xc7\xa2\x40\x5d\xbb\xf2\x39\xe0\x5b\x7b\x31\x9a\x73\xcd\x65\x66\x7d\x6e\xac\x4f\x75\x43\x26\xfe\xa5\x5a\x85\x0f\x10\x28\xdd\x88\xff\x80\x35\xfa\x55\xab\xb2\xb8\x63\x4f\x28\x4c\xfc\xa0\x34\x61\xfa\x27\xe3\xda\xc4\x7f\x31\x51\xa2\x0d\xf8\xa2\xb8\x84\x08\x2c\x2a\xd4\x21\x33\x82\x2b\x8b\x15\xff\xa4\xf2\x5c\xc9\xda\x79\xda\xac\x39\x78\x53\xd8\x6c\xae\xd6\x6b\x58\x72\x7a\xf6\x8d\xe3\x7b\xcc\xd5\x02\xfd\xe8\x7f\xb0\x1c\x4d\xc3\xe8\x50\xf4\x36\xf1\x69\xfb\x6b\x8f\x4c\x29\x9a\x44\xf3\x82\xb8\x92\xd1\x01\x8e\x09\xdf\xa9\x96\x74\x26\xb8\xa1\xc6\x54\x33\x99\x21\xc4\xb0\xd9\xd4\x79\xdd\x4c\x76\x8b\x7d\x9e\x2c\x2b\xd7\x15\x91\x36\x7d\xfb\xef\x16\xda\x1b\x68\x12\xab\x83\x7f\x93\x52\x11\xb3\x39\x79\x90\xce\xf2\x69\xb8\x0f\xaa\xd4\x09\xde\xd4\x62\xa2\x44\xcd\x48\xe9\xba\x12\x27\x03\x44\x1d\xa4\x60\x96\x33\xfd\x9a\xaa\xa5\xec\x71\x31\x09\x25\x23\x30\xeb\xc9\x78\x3a\x42\x91\x83\x08\x99\x0c\x33\x62\x04\x4b\x5e\xe3\x14\xe7\xac\x14\x14\x13\x27\x81\x0d\x15\x84\x79\x21\x18\xf9\x0f\x67\xbc\xaf\x06\x7d\x9c\xd2\xd8\xf6\x90\x0f\x41\xf9\x4d\x28\x10\x6f\xce\x84\x78\x62\xc9\x6b\x0f\x6f\x30\x7d\x0b\x0a\x1f\x70\xcc\x50\x70\xf9\x1a\x9c\x41\xd2\x64\xc0\xd3\x28\xcc\xa1\xd0\x68\x6b\x2d\xd0\xda\x49\xe8\x20\x63\x55\x0f\x0e\x4c\x99\x27\x4a\x62\xae\x5e\x78\x14\x6e\x5f\x6a\x11\x9a\x71\xf8\xcd\xcd\x95\xa2\x7a\xe2\x38\x35\xe8\x9a\x17\xf6\xd6\xd2\x92\x56\xad\x4b\xbf\xa1\x8d\x2b\xc7\x3e\x62\x22\x38\x4a\x3a\xbd\x20\xf7\x21\xee\xa6\xe2\x69\x9a\xf5\x71\xb9\x34\xc4\x64\x82\x66\x00\xb7\xd7\xc1\xe3\xfd\xac\xaa\xc2\x64\x28\x39\xb6\xc0\x39\x1a\xc3\xb2\xd3\x9e\xef\x1e\x58\x5f\xa1\x66\xe0\xed\x69\x68\x83\x13\x6e\xd2\x99\xaf\xde\x00\x9f\xc2\xf7\x70\x6d\x1b\x67\xb5\x08\xf5\x62\xd5\x3a\x0f\x33\xe2\xef\x02\xaa\x20\xd7\xce\x1d\x0d\xc4\xbb\x47\xa3\xc4\x02\xd3\x4e\xc4\xed\x72\x78\xcc\xad\x47\x2f\xea\x75\x08\xa5\xa6\xea\xe3\xe3\xab\xc9\x53\x7d\x89\xc9\x33\xa3\xb1\x9a\x4f\x2e\xfa\x1d\xd0\xcf\xdd\x28\x3f\x6a\xd1\xc3\x1b\xd4\x67\x8f\xea\x1d\x7d\x48\xcd\xec\xb0\xdc\xdb\x49\xfb\xe6\x05\xd3\xb4\x1a\x61\x4f\x2c\x0b\xb5\x66\x19\x4a\x9a\x75\x47\x9c\x5f\x5f\x0b\x9e\x90\xd2\xaa\x30\xbb\xb2\x25\x46\x38\xf3\x0b\xed\x52\x4b\xe3\x7a\x41\x9f\x55\x94\xc4\x69\x35\x4b\xb9\x29\x04\x5b\xcd\xf6\xec\xa6\x8e\x37\xee\x3e\x72\xae\x24\x27\x65\x09\x99\x91\x52\x62\xe4\x48\xf4\x66\x57\x69\x9e\xd5\x02\xf5\x19\xf6\x8f\x3d\xa8\xff\xbe\x9e\xce\x53\x4e\xe1\xd5\x74\xbe\x62\xea\x6f\xe9\x0f\x31\xb9\xdb\xd3\x8d\x99\x29\xee\x6e\x4e\x3a\x0f\xfb\xee\x98\x3e\xfe\x8c\xe0\xe0\x5c\xe4\x1d\x23\xaf\xcb\x22\xa1\xc0\x4c\xb3\x7c\x88\xca\xff\x2d\x29\x29\x37\x89\xd2\xe9\x19\x1a\x51\x17\xe9\xc2\xae\xdd\x26\x3c\xe1\xfb\xe5\xd1\xfd\x34\x8f\xb9\x21\x64\xb9\xdb\x4c\xf3\x9c\xe9\xd5\x49\x75\xda\xc5\x3a\xbd\xe2\x7b\x48\xcd\xc9\x3e\x44\xa6\x2f\x30\x4a\x28\xe7\x75\xdb\xa7\x15\x6b\x43\x87\x6a\x36\x10\xfc\x04\xf1\x16\x3f\x9c\x8f\x72\x17\xeb\x42\xfa\x10\xe9\x2f\x5c\xb3\xb3\x3c\x2e\x1e\x50\xe7\xdd\xc5\x85\xf3\x49\x75\x2c\x19\xe4\xaa\xd0\x5c\x69\x6e\x4f\x9c\xd7\xcd\xe9\xe5\xbb\xed\x12\xdc\xdc\x42\x14\x6d\x0f\x35\xdb\xf7\xd9\xde\xdd\x5a\x1f\x00\x80\xca\xcf\xe0\x02\xb7\x7e\x5c\xa6\xf8\xbe\x7d\xa5\x0e\xd1\xf6\x52\xe4\x79\xf0\x39\x5c\xe1\x9b\xe3\x18\x25\x9a\x13\x4f\x98\x88\xa6\xad\x61\x0b\xdf\xa6\x75\x0b\xd1\x6f\x3c\x7b\xf6\xb1\x50\x18\xac\x00\x99\x4c\xbb\xa8\x4b\xa6\x25\x97\x59\x34\x85\x2b\x89\x0e\x50\x0d\x33\x3d\x12\xeb\x77\x4c\x79\x99\x87\x47\xe3\x72\xae\x6c\x28\xbb\xba\x0b\x75\x34\xcc\x9d\x5a\x76\x62\xc8\xb4\xd5\xc4\xfd\x5d\x7f\x23\x73\xa1\x3d\x37\x5f\xa7\xb6\x30\x7a\xb1\x47\xa9\x35\x5a\xb1\x00\xd5\xce\xae\x5c\x90\x7a\xe7\x53\xf0\xb8\x8a\x5d\x25\x8f\x29\xbb\x43\xea\x5e\x75\x5b\x9d\x56\xc9\x2b\x92\xff\x1a\xe8\xe4\x49\x35\x00\xc6\x04\x67\xe6\xf4\x17\xe9\xfb\xd2\xfb\xf4\xd7\x8f\x01\xe0\xc3\x9f\x3f\x06\x1c\x8e\x7d\x03\x19\x4a\xbe\xf7\x21\xe4\xdf\x00\x00\x00\xff\xff\xde\xd1\xa3\x9d\x75\x1f\x00\x00"),
|
||||||
},
|
},
|
||||||
"/templates/email.tmpl": &vfsgen۰CompressedFileInfo{
|
"/templates/email.tmpl": &vfsgen۰CompressedFileInfo{
|
||||||
name: "email.tmpl",
|
name: "email.tmpl",
|
||||||
|
|
142
config/config.go
142
config/config.go
|
@ -269,6 +269,9 @@ func resolveFilepaths(baseDir string, cfg *Config) {
|
||||||
for _, cfg := range receiver.JiraConfigs {
|
for _, cfg := range receiver.JiraConfigs {
|
||||||
cfg.HTTPConfig.SetDirectory(baseDir)
|
cfg.HTTPConfig.SetDirectory(baseDir)
|
||||||
}
|
}
|
||||||
|
for _, cfg := range receiver.RocketchatConfigs {
|
||||||
|
cfg.HTTPConfig.SetDirectory(baseDir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,6 +367,14 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
return errors.New("at most one of smtp_auth_password & smtp_auth_password_file must be configured")
|
return errors.New("at most one of smtp_auth_password & smtp_auth_password_file must be configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Global.RocketchatToken != nil && len(c.Global.RocketchatTokenFile) > 0 {
|
||||||
|
return errors.New("at most one of rocketchat_token & rocketchat_token_file must be configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Global.RocketchatTokenID != nil && len(c.Global.RocketchatTokenIDFile) > 0 {
|
||||||
|
return errors.New("at most one of rocketchat_token_id & rocketchat_token_id_file must be configured")
|
||||||
|
}
|
||||||
|
|
||||||
names := map[string]struct{}{}
|
names := map[string]struct{}{}
|
||||||
|
|
||||||
for _, rcv := range c.Receivers {
|
for _, rcv := range c.Receivers {
|
||||||
|
@ -573,6 +584,28 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
jira.APIURL = c.Global.JiraAPIURL
|
jira.APIURL = c.Global.JiraAPIURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, rocketchat := range rcv.RocketchatConfigs {
|
||||||
|
if rocketchat.HTTPConfig == nil {
|
||||||
|
rocketchat.HTTPConfig = c.Global.HTTPConfig
|
||||||
|
}
|
||||||
|
if rocketchat.APIURL == nil {
|
||||||
|
rocketchat.APIURL = c.Global.RocketchatAPIURL
|
||||||
|
}
|
||||||
|
if rocketchat.TokenID == nil && len(rocketchat.TokenIDFile) == 0 {
|
||||||
|
if c.Global.RocketchatTokenID == nil && len(c.Global.RocketchatTokenIDFile) == 0 {
|
||||||
|
return errors.New("no global Rocketchat TokenID set either inline or in a file")
|
||||||
|
}
|
||||||
|
rocketchat.TokenID = c.Global.RocketchatTokenID
|
||||||
|
rocketchat.TokenIDFile = c.Global.RocketchatTokenIDFile
|
||||||
|
}
|
||||||
|
if rocketchat.Token == nil && len(rocketchat.TokenFile) == 0 {
|
||||||
|
if c.Global.RocketchatToken == nil && len(c.Global.RocketchatTokenFile) == 0 {
|
||||||
|
return errors.New("no global Rocketchat Token set either inline or in a file")
|
||||||
|
}
|
||||||
|
rocketchat.Token = c.Global.RocketchatToken
|
||||||
|
rocketchat.TokenFile = c.Global.RocketchatTokenFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
names[rcv.Name] = struct{}{}
|
names[rcv.Name] = struct{}{}
|
||||||
}
|
}
|
||||||
|
@ -665,17 +698,18 @@ func DefaultGlobalConfig() GlobalConfig {
|
||||||
defaultSMTPTLSConfig := commoncfg.TLSConfig{}
|
defaultSMTPTLSConfig := commoncfg.TLSConfig{}
|
||||||
|
|
||||||
return GlobalConfig{
|
return GlobalConfig{
|
||||||
ResolveTimeout: model.Duration(5 * time.Minute),
|
ResolveTimeout: model.Duration(5 * time.Minute),
|
||||||
HTTPConfig: &defaultHTTPConfig,
|
HTTPConfig: &defaultHTTPConfig,
|
||||||
SMTPHello: "localhost",
|
SMTPHello: "localhost",
|
||||||
SMTPRequireTLS: true,
|
SMTPRequireTLS: true,
|
||||||
SMTPTLSConfig: &defaultSMTPTLSConfig,
|
SMTPTLSConfig: &defaultSMTPTLSConfig,
|
||||||
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
|
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
|
||||||
OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"),
|
OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"),
|
||||||
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
|
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
|
||||||
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
|
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
|
||||||
TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
|
TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
|
||||||
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
|
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
|
||||||
|
RocketchatAPIURL: mustParseURL("https://open.rocket.chat/"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,31 +811,36 @@ type GlobalConfig struct {
|
||||||
|
|
||||||
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
|
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
|
||||||
|
|
||||||
JiraAPIURL *URL `yaml:"jira_api_url,omitempty" json:"jira_api_url,omitempty"`
|
JiraAPIURL *URL `yaml:"jira_api_url,omitempty" json:"jira_api_url,omitempty"`
|
||||||
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
|
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
|
||||||
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
|
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
|
||||||
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
|
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
|
||||||
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
|
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
|
||||||
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
|
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
|
||||||
SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
|
SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
|
||||||
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
|
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
|
||||||
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
|
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
|
||||||
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
|
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
|
||||||
SMTPTLSConfig *commoncfg.TLSConfig `yaml:"smtp_tls_config,omitempty" json:"smtp_tls_config,omitempty"`
|
SMTPTLSConfig *commoncfg.TLSConfig `yaml:"smtp_tls_config,omitempty" json:"smtp_tls_config,omitempty"`
|
||||||
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
|
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
|
||||||
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
|
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
|
||||||
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
|
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
|
||||||
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
|
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
|
||||||
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
|
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
|
||||||
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
|
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
|
||||||
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
|
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
|
||||||
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
|
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
|
||||||
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
|
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
|
||||||
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
|
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
|
||||||
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
|
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
|
||||||
VictorOpsAPIKeyFile string `yaml:"victorops_api_key_file,omitempty" json:"victorops_api_key_file,omitempty"`
|
VictorOpsAPIKeyFile string `yaml:"victorops_api_key_file,omitempty" json:"victorops_api_key_file,omitempty"`
|
||||||
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
|
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
|
||||||
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
|
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
|
||||||
|
RocketchatAPIURL *URL `yaml:"rocketchat_api_url,omitempty" json:"rocketchat_api_url,omitempty"`
|
||||||
|
RocketchatToken *Secret `yaml:"rocketchat_token,omitempty" json:"rocketchat_token,omitempty"`
|
||||||
|
RocketchatTokenFile string `yaml:"rocketchat_token_file,omitempty" json:"rocketchat_token_file,omitempty"`
|
||||||
|
RocketchatTokenID *Secret `yaml:"rocketchat_token_id,omitempty" json:"rocketchat_token_id,omitempty"`
|
||||||
|
RocketchatTokenIDFile string `yaml:"rocketchat_token_id_file,omitempty" json:"rocketchat_token_id_file,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig.
|
||||||
|
@ -933,21 +972,22 @@ type Receiver struct {
|
||||||
// A unique identifier for this receiver.
|
// A unique identifier for this receiver.
|
||||||
Name string `yaml:"name" json:"name"`
|
Name string `yaml:"name" json:"name"`
|
||||||
|
|
||||||
DiscordConfigs []*DiscordConfig `yaml:"discord_configs,omitempty" json:"discord_configs,omitempty"`
|
DiscordConfigs []*DiscordConfig `yaml:"discord_configs,omitempty" json:"discord_configs,omitempty"`
|
||||||
EmailConfigs []*EmailConfig `yaml:"email_configs,omitempty" json:"email_configs,omitempty"`
|
EmailConfigs []*EmailConfig `yaml:"email_configs,omitempty" json:"email_configs,omitempty"`
|
||||||
PagerdutyConfigs []*PagerdutyConfig `yaml:"pagerduty_configs,omitempty" json:"pagerduty_configs,omitempty"`
|
PagerdutyConfigs []*PagerdutyConfig `yaml:"pagerduty_configs,omitempty" json:"pagerduty_configs,omitempty"`
|
||||||
SlackConfigs []*SlackConfig `yaml:"slack_configs,omitempty" json:"slack_configs,omitempty"`
|
SlackConfigs []*SlackConfig `yaml:"slack_configs,omitempty" json:"slack_configs,omitempty"`
|
||||||
WebhookConfigs []*WebhookConfig `yaml:"webhook_configs,omitempty" json:"webhook_configs,omitempty"`
|
WebhookConfigs []*WebhookConfig `yaml:"webhook_configs,omitempty" json:"webhook_configs,omitempty"`
|
||||||
OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs,omitempty" json:"opsgenie_configs,omitempty"`
|
OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs,omitempty" json:"opsgenie_configs,omitempty"`
|
||||||
WechatConfigs []*WechatConfig `yaml:"wechat_configs,omitempty" json:"wechat_configs,omitempty"`
|
WechatConfigs []*WechatConfig `yaml:"wechat_configs,omitempty" json:"wechat_configs,omitempty"`
|
||||||
PushoverConfigs []*PushoverConfig `yaml:"pushover_configs,omitempty" json:"pushover_configs,omitempty"`
|
PushoverConfigs []*PushoverConfig `yaml:"pushover_configs,omitempty" json:"pushover_configs,omitempty"`
|
||||||
VictorOpsConfigs []*VictorOpsConfig `yaml:"victorops_configs,omitempty" json:"victorops_configs,omitempty"`
|
VictorOpsConfigs []*VictorOpsConfig `yaml:"victorops_configs,omitempty" json:"victorops_configs,omitempty"`
|
||||||
SNSConfigs []*SNSConfig `yaml:"sns_configs,omitempty" json:"sns_configs,omitempty"`
|
SNSConfigs []*SNSConfig `yaml:"sns_configs,omitempty" json:"sns_configs,omitempty"`
|
||||||
TelegramConfigs []*TelegramConfig `yaml:"telegram_configs,omitempty" json:"telegram_configs,omitempty"`
|
TelegramConfigs []*TelegramConfig `yaml:"telegram_configs,omitempty" json:"telegram_configs,omitempty"`
|
||||||
WebexConfigs []*WebexConfig `yaml:"webex_configs,omitempty" json:"webex_configs,omitempty"`
|
WebexConfigs []*WebexConfig `yaml:"webex_configs,omitempty" json:"webex_configs,omitempty"`
|
||||||
MSTeamsConfigs []*MSTeamsConfig `yaml:"msteams_configs,omitempty" json:"msteams_configs,omitempty"`
|
MSTeamsConfigs []*MSTeamsConfig `yaml:"msteams_configs,omitempty" json:"msteams_configs,omitempty"`
|
||||||
MSTeamsV2Configs []*MSTeamsV2Config `yaml:"msteamsv2_configs,omitempty" json:"msteamsv2_configs,omitempty"`
|
MSTeamsV2Configs []*MSTeamsV2Config `yaml:"msteamsv2_configs,omitempty" json:"msteamsv2_configs,omitempty"`
|
||||||
JiraConfigs []*JiraConfig `yaml:"jira_configs,omitempty" json:"jira_configs,omitempty"`
|
JiraConfigs []*JiraConfig `yaml:"jira_configs,omitempty" json:"jira_configs,omitempty"`
|
||||||
|
RocketchatConfigs []*RocketchatConfig `yaml:"rocketchat_configs,omitempty" json:"rocketchat_configs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for Receiver.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface for Receiver.
|
||||||
|
|
|
@ -872,14 +872,15 @@ func TestEmptyFieldsAndRegex(t *testing.T) {
|
||||||
SMTPTLSConfig: &commoncfg.TLSConfig{
|
SMTPTLSConfig: &commoncfg.TLSConfig{
|
||||||
InsecureSkipVerify: false,
|
InsecureSkipVerify: false,
|
||||||
},
|
},
|
||||||
SlackAPIURL: (*SecretURL)(mustParseURL("http://slack.example.com/")),
|
SlackAPIURL: (*SecretURL)(mustParseURL("http://slack.example.com/")),
|
||||||
SMTPRequireTLS: true,
|
SMTPRequireTLS: true,
|
||||||
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
|
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
|
||||||
OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"),
|
OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"),
|
||||||
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
|
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
|
||||||
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
|
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
|
||||||
TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
|
TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
|
||||||
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
|
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
|
||||||
|
RocketchatAPIURL: mustParseURL("https://open.rocket.chat/"),
|
||||||
},
|
},
|
||||||
|
|
||||||
Templates: []string{
|
Templates: []string{
|
||||||
|
@ -1203,6 +1204,100 @@ func TestInvalidSNSConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRocketchatDefaultToken(t *testing.T) {
|
||||||
|
conf, err := LoadFile("testdata/conf.rocketchat-default-token.yml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing %s: %s", "testdata/conf.rocketchat-default-token.yml", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultToken := conf.Global.RocketchatToken
|
||||||
|
overrideToken := Secret("token456")
|
||||||
|
if defaultToken != conf.Receivers[0].RocketchatConfigs[0].Token {
|
||||||
|
t.Fatalf("Invalid rocketchat key: %s\nExpected: %s", string(*conf.Receivers[0].RocketchatConfigs[0].Token), string(*defaultToken))
|
||||||
|
}
|
||||||
|
if overrideToken != *conf.Receivers[1].RocketchatConfigs[0].Token {
|
||||||
|
t.Errorf("Invalid rocketchat key: %s\nExpected: %s", string(*conf.Receivers[0].RocketchatConfigs[0].Token), string(overrideToken))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRocketchatDefaultTokenID(t *testing.T) {
|
||||||
|
conf, err := LoadFile("testdata/conf.rocketchat-default-token.yml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing %s: %s", "testdata/conf.rocketchat-default-token.yml", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTokenID := conf.Global.RocketchatTokenID
|
||||||
|
overrideTokenID := Secret("id456")
|
||||||
|
if defaultTokenID != conf.Receivers[0].RocketchatConfigs[0].TokenID {
|
||||||
|
t.Fatalf("Invalid rocketchat key: %s\nExpected: %s", string(*conf.Receivers[0].RocketchatConfigs[0].TokenID), string(*defaultTokenID))
|
||||||
|
}
|
||||||
|
if overrideTokenID != *conf.Receivers[1].RocketchatConfigs[0].TokenID {
|
||||||
|
t.Errorf("Invalid rocketchat key: %s\nExpected: %s", string(*conf.Receivers[0].RocketchatConfigs[0].TokenID), string(overrideTokenID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRocketchatDefaultTokenFile(t *testing.T) {
|
||||||
|
conf, err := LoadFile("testdata/conf.rocketchat-default-token-file.yml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing %s: %s", "testdata/conf.rocketchat-default-token-file.yml", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTokenFile := conf.Global.RocketchatTokenFile
|
||||||
|
overrideTokenFile := "/override_file"
|
||||||
|
if defaultTokenFile != conf.Receivers[0].RocketchatConfigs[0].TokenFile {
|
||||||
|
t.Fatalf("Invalid Rocketchat key_file: %s\nExpected: %s", conf.Receivers[0].RocketchatConfigs[0].TokenFile, defaultTokenFile)
|
||||||
|
}
|
||||||
|
if overrideTokenFile != conf.Receivers[1].RocketchatConfigs[0].TokenFile {
|
||||||
|
t.Errorf("Invalid Rocketchat key_file: %s\nExpected: %s", conf.Receivers[0].RocketchatConfigs[0].TokenFile, overrideTokenFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRocketchatDefaultIDTokenFile(t *testing.T) {
|
||||||
|
conf, err := LoadFile("testdata/conf.rocketchat-default-token-file.yml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error parsing %s: %s", "testdata/conf.rocketchat-default-token-file.yml", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTokenIDFile := conf.Global.RocketchatTokenIDFile
|
||||||
|
overrideTokenIDFile := "/override_file"
|
||||||
|
if defaultTokenIDFile != conf.Receivers[0].RocketchatConfigs[0].TokenIDFile {
|
||||||
|
t.Fatalf("Invalid Rocketchat key_file: %s\nExpected: %s", conf.Receivers[0].RocketchatConfigs[0].TokenIDFile, defaultTokenIDFile)
|
||||||
|
}
|
||||||
|
if overrideTokenIDFile != conf.Receivers[1].RocketchatConfigs[0].TokenIDFile {
|
||||||
|
t.Errorf("Invalid Rocketchat key_file: %s\nExpected: %s", conf.Receivers[0].RocketchatConfigs[0].TokenIDFile, overrideTokenIDFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRocketchatBothTokenAndTokenFile(t *testing.T) {
|
||||||
|
_, err := LoadFile("testdata/conf.rocketchat-both-token-and-tokenfile.yml")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected an error parsing %s: %s", "testdata/conf.rocketchat-both-token-and-tokenfile.yml", err)
|
||||||
|
}
|
||||||
|
if err.Error() != "at most one of rocketchat_token & rocketchat_token_file must be configured" {
|
||||||
|
t.Errorf("Expected: %s\nGot: %s", "at most one of rocketchat_token & rocketchat_token_file must be configured", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRocketchatBothTokenIDAndTokenIDFile(t *testing.T) {
|
||||||
|
_, err := LoadFile("testdata/conf.rocketchat-both-tokenid-and-tokenidfile.yml")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected an error parsing %s: %s", "testdata/conf.rocketchat-both-tokenid-and-tokenidfile.yml", err)
|
||||||
|
}
|
||||||
|
if err.Error() != "at most one of rocketchat_token_id & rocketchat_token_id_file must be configured" {
|
||||||
|
t.Errorf("Expected: %s\nGot: %s", "at most one of rocketchat_token_id & rocketchat_token_id_file must be configured", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRocketchatNoToken(t *testing.T) {
|
||||||
|
_, err := LoadFile("testdata/conf.rocketchat-no-token.yml")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected an error parsing %s: %s", "testdata/conf.rocketchat-no-token.yml", err)
|
||||||
|
}
|
||||||
|
if err.Error() != "no global Rocketchat Token set either inline or in a file" {
|
||||||
|
t.Errorf("Expected: %s\nGot: %s", "no global Rocketchat Token set either inline or in a file", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnmarshalHostPort(t *testing.T) {
|
func TestUnmarshalHostPort(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
in string
|
in string
|
||||||
|
|
|
@ -99,6 +99,18 @@ var (
|
||||||
CallbackID: `{{ template "slack.default.callbackid" . }}`,
|
CallbackID: `{{ template "slack.default.callbackid" . }}`,
|
||||||
Footer: `{{ template "slack.default.footer" . }}`,
|
Footer: `{{ template "slack.default.footer" . }}`,
|
||||||
}
|
}
|
||||||
|
// DefaultRocketchatConfig defines default values for Rocketchat configurations.
|
||||||
|
DefaultRocketchatConfig = RocketchatConfig{
|
||||||
|
NotifierConfig: NotifierConfig{
|
||||||
|
VSendResolved: false,
|
||||||
|
},
|
||||||
|
Color: `{{ if eq .Status "firing" }}red{{ else }}green{{ end }}`,
|
||||||
|
Emoji: `{{ template "rocketchat.default.emoji" . }}`,
|
||||||
|
IconURL: `{{ template "rocketchat.default.iconurl" . }}`,
|
||||||
|
Text: `{{ template "rocketchat.default.text" . }}`,
|
||||||
|
Title: `{{ template "rocketchat.default.title" . }}`,
|
||||||
|
TitleLink: `{{ template "rocketchat.default.titlelink" . }}`,
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultOpsGenieConfig defines default values for OpsGenie configurations.
|
// DefaultOpsGenieConfig defines default values for OpsGenie configurations.
|
||||||
DefaultOpsGenieConfig = OpsGenieConfig{
|
DefaultOpsGenieConfig = OpsGenieConfig{
|
||||||
|
@ -907,6 +919,73 @@ func (c *JiraConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
if c.IssueType == "" {
|
if c.IssueType == "" {
|
||||||
return errors.New("missing issue_type in jira_config")
|
return errors.New("missing issue_type in jira_config")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type RocketchatAttachmentField struct {
|
||||||
|
Short *bool `json:"short"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Value string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProcessingTypeSendMessage = "sendMessage"
|
||||||
|
ProcessingTypeRespondWithMessage = "respondWithMessage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RocketchatAttachmentAction struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
ImageURL string `json:"image_url,omitempty"`
|
||||||
|
IsWebView bool `json:"is_webview"`
|
||||||
|
WebviewHeightRatio string `json:"webview_height_ratio,omitempty"`
|
||||||
|
Msg string `json:"msg,omitempty"`
|
||||||
|
MsgInChatWindow bool `json:"msg_in_chat_window"`
|
||||||
|
MsgProcessingType string `json:"msg_processing_type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RocketchatConfig configures notifications via Rocketchat.
|
||||||
|
type RocketchatConfig struct {
|
||||||
|
NotifierConfig `yaml:",inline" json:",inline"`
|
||||||
|
|
||||||
|
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
|
||||||
|
|
||||||
|
APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"`
|
||||||
|
TokenID *Secret `yaml:"token_id,omitempty" json:"token_id,omitempty"`
|
||||||
|
TokenIDFile string `yaml:"token_id_file,omitempty" json:"token_id_file,omitempty"`
|
||||||
|
Token *Secret `yaml:"token,omitempty" json:"token,omitempty"`
|
||||||
|
TokenFile string `yaml:"token_file,omitempty" json:"token_file,omitempty"`
|
||||||
|
|
||||||
|
// RocketChat channel override, (like #other-channel or @username).
|
||||||
|
Channel string `yaml:"channel,omitempty" json:"channel,omitempty"`
|
||||||
|
|
||||||
|
Color string `yaml:"color,omitempty" json:"color,omitempty"`
|
||||||
|
Title string `yaml:"title,omitempty" json:"title,omitempty"`
|
||||||
|
TitleLink string `yaml:"title_link,omitempty" json:"title_link,omitempty"`
|
||||||
|
Text string `yaml:"text,omitempty" json:"text,omitempty"`
|
||||||
|
Fields []*RocketchatAttachmentField `yaml:"fields,omitempty" json:"fields,omitempty"`
|
||||||
|
ShortFields bool `yaml:"short_fields" json:"short_fields,omitempty"`
|
||||||
|
Emoji string `yaml:"emoji,omitempty" json:"emoji,omitempty"`
|
||||||
|
IconURL string `yaml:"icon_url,omitempty" json:"icon_url,omitempty"`
|
||||||
|
ImageURL string `yaml:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
ThumbURL string `yaml:"thumb_url,omitempty" json:"thumb_url,omitempty"`
|
||||||
|
LinkNames bool `yaml:"link_names" json:"link_names,omitempty"`
|
||||||
|
Actions []*RocketchatAttachmentAction `yaml:"actions,omitempty" json:"actions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
func (c *RocketchatConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
*c = DefaultRocketchatConfig
|
||||||
|
type plain RocketchatConfig
|
||||||
|
if err := unmarshal((*plain)(c)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.Token != nil && len(c.TokenFile) > 0 {
|
||||||
|
return errors.New("at most one of token & token_file must be configured")
|
||||||
|
}
|
||||||
|
if c.TokenID != nil && len(c.TokenIDFile) > 0 {
|
||||||
|
return errors.New("at most one of token_id & token_id_file must be configured")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/prometheus/alertmanager/notify/opsgenie"
|
"github.com/prometheus/alertmanager/notify/opsgenie"
|
||||||
"github.com/prometheus/alertmanager/notify/pagerduty"
|
"github.com/prometheus/alertmanager/notify/pagerduty"
|
||||||
"github.com/prometheus/alertmanager/notify/pushover"
|
"github.com/prometheus/alertmanager/notify/pushover"
|
||||||
|
"github.com/prometheus/alertmanager/notify/rocketchat"
|
||||||
"github.com/prometheus/alertmanager/notify/slack"
|
"github.com/prometheus/alertmanager/notify/slack"
|
||||||
"github.com/prometheus/alertmanager/notify/sns"
|
"github.com/prometheus/alertmanager/notify/sns"
|
||||||
"github.com/prometheus/alertmanager/notify/telegram"
|
"github.com/prometheus/alertmanager/notify/telegram"
|
||||||
|
@ -100,6 +101,9 @@ func BuildReceiverIntegrations(nc config.Receiver, tmpl *template.Template, logg
|
||||||
for i, c := range nc.JiraConfigs {
|
for i, c := range nc.JiraConfigs {
|
||||||
add("jira", i, c, func(l log.Logger) (notify.Notifier, error) { return jira.New(c, tmpl, l, httpOpts...) })
|
add("jira", i, c, func(l log.Logger) (notify.Notifier, error) { return jira.New(c, tmpl, l, httpOpts...) })
|
||||||
}
|
}
|
||||||
|
for i, c := range nc.RocketchatConfigs {
|
||||||
|
add("rocketchat", i, c, func(l log.Logger) (notify.Notifier, error) { return rocketchat.New(c, tmpl, l, httpOpts...) })
|
||||||
|
}
|
||||||
|
|
||||||
if errs.Len() > 0 {
|
if errs.Len() > 0 {
|
||||||
return nil, &errs
|
return nil, &errs
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
global:
|
||||||
|
rocketchat_token_file: /global_file
|
||||||
|
rocketchat_token: token123
|
||||||
|
route:
|
||||||
|
group_by: ['alertname', 'cluster', 'service']
|
||||||
|
group_wait: 30s
|
||||||
|
group_interval: 5m
|
||||||
|
repeat_interval: 3h
|
||||||
|
receiver: team-Y-rocketchat
|
||||||
|
routes:
|
||||||
|
- match:
|
||||||
|
service: foo
|
||||||
|
receiver: team-X-rocketchat
|
||||||
|
receivers:
|
||||||
|
- name: 'team-X-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-X'
|
||||||
|
- name: 'team-Y-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-Y'
|
|
@ -0,0 +1,20 @@
|
||||||
|
global:
|
||||||
|
rocketchat_token_id_file: /global_file
|
||||||
|
rocketchat_token_id: id123
|
||||||
|
route:
|
||||||
|
group_by: ['alertname', 'cluster', 'service']
|
||||||
|
group_wait: 30s
|
||||||
|
group_interval: 5m
|
||||||
|
repeat_interval: 3h
|
||||||
|
receiver: team-Y-rocketchat
|
||||||
|
routes:
|
||||||
|
- match:
|
||||||
|
service: foo
|
||||||
|
receiver: team-X-rocketchat
|
||||||
|
receivers:
|
||||||
|
- name: 'team-X-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-X'
|
||||||
|
- name: 'team-Y-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-Y'
|
|
@ -0,0 +1,22 @@
|
||||||
|
global:
|
||||||
|
rocketchat_token_file: /global_file
|
||||||
|
rocketchat_token_id_file: /etc/alertmanager/rocketchat_token_id
|
||||||
|
route:
|
||||||
|
group_by: ['alertname', 'cluster', 'service']
|
||||||
|
group_wait: 30s
|
||||||
|
group_interval: 5m
|
||||||
|
repeat_interval: 3h
|
||||||
|
receiver: team-Y-rocketchat
|
||||||
|
routes:
|
||||||
|
- match:
|
||||||
|
service: foo
|
||||||
|
receiver: team-X-rocketchat
|
||||||
|
receivers:
|
||||||
|
- name: 'team-X-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-X'
|
||||||
|
- name: 'team-Y-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-Y'
|
||||||
|
token_file: /override_file
|
||||||
|
token_id_file: /override_file
|
|
@ -0,0 +1,22 @@
|
||||||
|
global:
|
||||||
|
rocketchat_token: token123
|
||||||
|
rocketchat_token_id: id123
|
||||||
|
route:
|
||||||
|
group_by: ['alertname', 'cluster', 'service']
|
||||||
|
group_wait: 30s
|
||||||
|
group_interval: 5m
|
||||||
|
repeat_interval: 3h
|
||||||
|
receiver: team-Y-rocketchat
|
||||||
|
routes:
|
||||||
|
- match:
|
||||||
|
service: foo
|
||||||
|
receiver: team-X-rocketchat
|
||||||
|
receivers:
|
||||||
|
- name: 'team-X-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-X'
|
||||||
|
- name: 'team-Y-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-Y'
|
||||||
|
token: token456
|
||||||
|
token_id: id456
|
|
@ -0,0 +1,19 @@
|
||||||
|
global:
|
||||||
|
rocketchat_token_id: id123
|
||||||
|
route:
|
||||||
|
group_by: ['alertname', 'cluster', 'service']
|
||||||
|
group_wait: 30s
|
||||||
|
group_interval: 5m
|
||||||
|
repeat_interval: 3h
|
||||||
|
receiver: team-Y-rocketchat
|
||||||
|
routes:
|
||||||
|
- match:
|
||||||
|
service: foo
|
||||||
|
receiver: team-X-rocketchat
|
||||||
|
receivers:
|
||||||
|
- name: 'team-X-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-X'
|
||||||
|
- name: 'team-Y-rocketchat'
|
||||||
|
rocketchat_configs:
|
||||||
|
- channel: '#team-Y'
|
|
@ -97,7 +97,7 @@ global:
|
||||||
# The default TLS configuration for SMTP receivers
|
# The default TLS configuration for SMTP receivers
|
||||||
[ smtp_tls_config: <tls_config> ]
|
[ smtp_tls_config: <tls_config> ]
|
||||||
|
|
||||||
# Default settings for the JIRA integration.
|
# Default settings for the JIRA integration.
|
||||||
[ jira_api_url: <string> ]
|
[ jira_api_url: <string> ]
|
||||||
|
|
||||||
# The API URL to use for Slack notifications.
|
# The API URL to use for Slack notifications.
|
||||||
|
@ -110,6 +110,11 @@ global:
|
||||||
[ opsgenie_api_key: <secret> ]
|
[ opsgenie_api_key: <secret> ]
|
||||||
[ opsgenie_api_key_file: <filepath> ]
|
[ opsgenie_api_key_file: <filepath> ]
|
||||||
[ opsgenie_api_url: <string> | default = "https://api.opsgenie.com/" ]
|
[ opsgenie_api_url: <string> | default = "https://api.opsgenie.com/" ]
|
||||||
|
[ rocketchat_api_url: <string> | default = "https://open.rocket.chat/" ]
|
||||||
|
[ rocketchat_token: <secret> ]
|
||||||
|
[ rocketchat_token_file: <filepath> ]
|
||||||
|
[ rocketchat_token_id: <secret> ]
|
||||||
|
[ rocketchat_token_id_file: <filepath> ]
|
||||||
[ wechat_api_url: <string> | default = "https://qyapi.weixin.qq.com/cgi-bin/" ]
|
[ wechat_api_url: <string> | default = "https://qyapi.weixin.qq.com/cgi-bin/" ]
|
||||||
[ wechat_api_secret: <secret> ]
|
[ wechat_api_secret: <secret> ]
|
||||||
[ wechat_api_corp_id: <string> ]
|
[ wechat_api_corp_id: <string> ]
|
||||||
|
@ -710,6 +715,8 @@ pagerduty_configs:
|
||||||
[ - <pagerduty_config>, ... ]
|
[ - <pagerduty_config>, ... ]
|
||||||
pushover_configs:
|
pushover_configs:
|
||||||
[ - <pushover_config>, ... ]
|
[ - <pushover_config>, ... ]
|
||||||
|
rocket_configs:
|
||||||
|
[ - <rocketchat_config>, ... ]
|
||||||
slack_configs:
|
slack_configs:
|
||||||
[ - <slack_config>, ... ]
|
[ - <slack_config>, ... ]
|
||||||
sns_configs:
|
sns_configs:
|
||||||
|
@ -981,7 +988,7 @@ Microsoft Teams v2 notifications using the new message format with adaptive card
|
||||||
JIRA notifications are sent via [JIRA Rest API v2](https://developer.atlassian.com/cloud/jira/platform/rest/v2/intro/)
|
JIRA notifications are sent via [JIRA Rest API v2](https://developer.atlassian.com/cloud/jira/platform/rest/v2/intro/)
|
||||||
or [JIRA REST API v3](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/#version).
|
or [JIRA REST API v3](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/#version).
|
||||||
|
|
||||||
Note: This integration is only tested against a Jira Cloud instance.
|
Note: This integration is only tested against a Jira Cloud instance.
|
||||||
Jira Data Center (on premise instance) can work, but it's not guaranteed.
|
Jira Data Center (on premise instance) can work, but it's not guaranteed.
|
||||||
|
|
||||||
Both APIs have the same feature set. The difference is that V2 supports [Wiki Markup](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)
|
Both APIs have the same feature set. The difference is that V2 supports [Wiki Markup](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)
|
||||||
|
@ -1006,7 +1013,7 @@ project: <string>
|
||||||
[ description: <tmpl_string> | default = '{{ template "jira.default.description" . }}' ]
|
[ description: <tmpl_string> | default = '{{ template "jira.default.description" . }}' ]
|
||||||
|
|
||||||
# Labels to be added to the issue.
|
# Labels to be added to the issue.
|
||||||
labels:
|
labels:
|
||||||
[ - <tmpl_string> ... ]
|
[ - <tmpl_string> ... ]
|
||||||
|
|
||||||
# Priority of the issue.
|
# Priority of the issue.
|
||||||
|
@ -1283,6 +1290,62 @@ token_file: <filepath>
|
||||||
[ http_config: <http_config> | default = global.http_config ]
|
[ http_config: <http_config> | default = global.http_config ]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `<rocketchat_config>`
|
||||||
|
|
||||||
|
Rocketchat notifications are sent via the [Rocketchat REST API](https://developer.rocket.chat/reference/api/rest-api/endpoints/messaging/chat-endpoints/postmessage).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Whether to notify about resolved alerts.
|
||||||
|
[ send_resolved: <boolean> | default = true ]
|
||||||
|
[ api_url: <string> | default = global.rocketchat_api_url ]
|
||||||
|
[ channel: <tmpl_string> | default = global.rocketchat_api_url ]
|
||||||
|
|
||||||
|
# The sender token and token_id
|
||||||
|
# See https://docs.rocket.chat/use-rocket.chat/user-guides/user-panel/my-account#personal-access-tokens
|
||||||
|
# token and token_file are mutually exclusive.
|
||||||
|
# token_id and token_id_file are mutually exclusive.
|
||||||
|
token: <secret>
|
||||||
|
token_file: <filepath>
|
||||||
|
token_id: <secret>
|
||||||
|
token_id_file: <filepath>
|
||||||
|
|
||||||
|
|
||||||
|
[ color: <tmpl_string | default '{{ if eq .Status "firing" }}red{{ else }}green{{ end }}' ]
|
||||||
|
[ emoji <tmpl_string | default = '{{ template "rocketchat.default.emoji" . }}'
|
||||||
|
[ icon_url <tmpl_string | default = '{{ template "rocketchat.default.iconurl" . }}'
|
||||||
|
[ text <tmpl_string | default = '{{ template "rocketchat.default.text" . }}'
|
||||||
|
[ title <tmpl_string | default = '{{ template "rocketchat.default.title" . }}'
|
||||||
|
[ titleLink <tmpl_string | default = '{{ template "rocketchat.default.titlelink" . }}'
|
||||||
|
[ text: <tmpl_string | default = '{{ template "rocketchat.default.text" . }}'
|
||||||
|
fields:
|
||||||
|
[ <rocketchat_field_config> ... ]
|
||||||
|
[ image_url <tmpl_string> ]
|
||||||
|
[ thumb_url <tmpl_string> ]
|
||||||
|
[ link_names <tmpl_string> ]
|
||||||
|
[ short_fields: <boolean> | default = false ]
|
||||||
|
actions:
|
||||||
|
[ <rocketchat_action_config> ... ]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `<rocketchat_field_config>`
|
||||||
|
|
||||||
|
The fields are documented in the [Rocketchat API documentation](https://developer.rocket.chat/reference/api/rest-api/endpoints/messaging/chat-endpoints/postmessage#attachment-field-objects).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
[ title: <tmpl_string> ]
|
||||||
|
[ value: <tmpl_string> ]
|
||||||
|
[ short: <boolean> | default = rocketchat_config.short_fields ]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `<rocketchat_action_config>`
|
||||||
|
The fields are documented in the [Rocketchat API api models](https://github.com/RocketChat/Rocket.Chat.Go.SDK/blob/master/models/message.go).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
[ type: <tmpl_string> | ignored, only "button" is supported ]
|
||||||
|
[ text: <tmpl_string> ]
|
||||||
|
[ url: <tmpl_string> ]
|
||||||
|
[ msg: <tmpl_string> ]
|
||||||
|
|
||||||
### `<slack_config>`
|
### `<slack_config>`
|
||||||
|
|
||||||
Slack notifications can be sent via [Incoming webhooks](https://api.slack.com/messaging/webhooks) or [Bot tokens](https://api.slack.com/authentication/token-types).
|
Slack notifications can be sent via [Incoming webhooks](https://api.slack.com/messaging/webhooks) or [Bot tokens](https://api.slack.com/authentication/token-types).
|
||||||
|
|
|
@ -367,6 +367,7 @@ func (m *Metrics) InitializeFor(receiver map[string][]Integration) {
|
||||||
"msteams",
|
"msteams",
|
||||||
"msteamsv2",
|
"msteamsv2",
|
||||||
"jira",
|
"jira",
|
||||||
|
"rocketchat",
|
||||||
} {
|
} {
|
||||||
m.numNotifications.WithLabelValues(integration)
|
m.numNotifications.WithLabelValues(integration)
|
||||||
m.numNotificationRequestsTotal.WithLabelValues(integration)
|
m.numNotificationRequestsTotal.WithLabelValues(integration)
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
// Copyright 2022 Prometheus Team
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package rocketchat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-kit/log"
|
||||||
|
"github.com/go-kit/log/level"
|
||||||
|
commoncfg "github.com/prometheus/common/config"
|
||||||
|
|
||||||
|
"github.com/prometheus/alertmanager/config"
|
||||||
|
"github.com/prometheus/alertmanager/notify"
|
||||||
|
"github.com/prometheus/alertmanager/template"
|
||||||
|
"github.com/prometheus/alertmanager/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxTitleLenRunes = 1024
|
||||||
|
|
||||||
|
type Notifier struct {
|
||||||
|
conf *config.RocketchatConfig
|
||||||
|
tmpl *template.Template
|
||||||
|
logger log.Logger
|
||||||
|
client *http.Client
|
||||||
|
retrier *notify.Retrier
|
||||||
|
token string
|
||||||
|
tokenID string
|
||||||
|
|
||||||
|
postJSONFunc func(ctx context.Context, client *http.Client, url string, body io.Reader) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostMessage Payload for postmessage rest API
|
||||||
|
//
|
||||||
|
// https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage/
|
||||||
|
type Attachment struct {
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
TitleLink string `json:"title_link,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
ImageURL string `json:"image_url,omitempty"`
|
||||||
|
ThumbURL string `json:"thumb_url,omitempty"`
|
||||||
|
Color string `json:"color,omitempty"`
|
||||||
|
Fields []config.RocketchatAttachmentField `json:"fields,omitempty"`
|
||||||
|
Actions []config.RocketchatAttachmentAction `json:"actions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostMessage Payload for postmessage rest API
|
||||||
|
//
|
||||||
|
// https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage/
|
||||||
|
type PostMessage struct {
|
||||||
|
Channel string `json:"channel,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
ParseUrls bool `json:"parseUrls,omitempty"`
|
||||||
|
Alias string `json:"alias,omitempty"`
|
||||||
|
Emoji string `json:"emoji,omitempty"`
|
||||||
|
Avatar string `json:"avatar,omitempty"`
|
||||||
|
Attachments []Attachment `json:"attachments,omitempty"`
|
||||||
|
Actions []config.RocketchatAttachmentAction `json:"actions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type rocketchatRoundTripper struct {
|
||||||
|
wrapped http.RoundTripper
|
||||||
|
token string
|
||||||
|
tokenID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *rocketchatRoundTripper) RoundTrip(req *http.Request) (res *http.Response, e error) {
|
||||||
|
req.Header.Set("X-Auth-Token", t.token)
|
||||||
|
req.Header.Set("X-User-Id", t.tokenID)
|
||||||
|
return t.wrapped.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new Rocketchat notification handler.
|
||||||
|
func New(c *config.RocketchatConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
|
||||||
|
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "rocketchat", httpOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token, err := getToken(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenID, err := getTokenID(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Transport = &rocketchatRoundTripper{wrapped: client.Transport, token: token, tokenID: tokenID}
|
||||||
|
return &Notifier{
|
||||||
|
conf: c,
|
||||||
|
tmpl: t,
|
||||||
|
logger: l,
|
||||||
|
client: client,
|
||||||
|
retrier: ¬ify.Retrier{},
|
||||||
|
postJSONFunc: notify.PostJSON,
|
||||||
|
token: token,
|
||||||
|
tokenID: tokenID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTokenID(c *config.RocketchatConfig) (string, error) {
|
||||||
|
if len(c.TokenIDFile) > 0 {
|
||||||
|
content, err := os.ReadFile(c.TokenIDFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not read %s: %w", c.TokenIDFile, err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(content)), nil
|
||||||
|
}
|
||||||
|
return string(*c.TokenID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getToken(c *config.RocketchatConfig) (string, error) {
|
||||||
|
if len(c.TokenFile) > 0 {
|
||||||
|
content, err := os.ReadFile(c.TokenFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not read %s: %w", c.TokenFile, err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(content)), nil
|
||||||
|
}
|
||||||
|
return string(*c.Token), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify implements the Notifier interface.
|
||||||
|
func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
data := notify.GetTemplateData(ctx, n.tmpl, as, n.logger)
|
||||||
|
tmplText := notify.TmplText(n.tmpl, data, &err)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
title := tmplText(n.conf.Title)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
title, truncated := notify.TruncateInRunes(title, maxTitleLenRunes)
|
||||||
|
if truncated {
|
||||||
|
key, err := notify.ExtractGroupKey(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
level.Warn(n.logger).Log("msg", "Truncated title", "key", key, "max_runes", maxTitleLenRunes)
|
||||||
|
}
|
||||||
|
att := &Attachment{
|
||||||
|
Title: title,
|
||||||
|
TitleLink: tmplText(n.conf.TitleLink),
|
||||||
|
Text: tmplText(n.conf.Text),
|
||||||
|
ImageURL: tmplText(n.conf.ImageURL),
|
||||||
|
ThumbURL: tmplText(n.conf.ThumbURL),
|
||||||
|
Color: tmplText(n.conf.Color),
|
||||||
|
}
|
||||||
|
numFields := len(n.conf.Fields)
|
||||||
|
if numFields > 0 {
|
||||||
|
fields := make([]config.RocketchatAttachmentField, numFields)
|
||||||
|
for index, field := range n.conf.Fields {
|
||||||
|
// Check if short was defined for the field otherwise fallback to the global setting
|
||||||
|
var short bool
|
||||||
|
if field.Short != nil {
|
||||||
|
short = *field.Short
|
||||||
|
} else {
|
||||||
|
short = n.conf.ShortFields
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild the field by executing any templates and setting the new value for short
|
||||||
|
fields[index] = config.RocketchatAttachmentField{
|
||||||
|
Title: tmplText(field.Title),
|
||||||
|
Value: tmplText(field.Value),
|
||||||
|
Short: &short,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
att.Fields = fields
|
||||||
|
}
|
||||||
|
numActions := len(n.conf.Actions)
|
||||||
|
if numActions > 0 {
|
||||||
|
actions := make([]config.RocketchatAttachmentAction, numActions)
|
||||||
|
for index, action := range n.conf.Actions {
|
||||||
|
actions[index] = config.RocketchatAttachmentAction{
|
||||||
|
Type: "button", // Only button type is supported
|
||||||
|
Text: tmplText(action.Text),
|
||||||
|
URL: tmplText(action.URL),
|
||||||
|
Msg: tmplText(action.Msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
att.Actions = actions
|
||||||
|
}
|
||||||
|
|
||||||
|
body := &PostMessage{
|
||||||
|
Channel: n.conf.Channel,
|
||||||
|
Emoji: tmplText(n.conf.Emoji),
|
||||||
|
Avatar: tmplText(n.conf.IconURL),
|
||||||
|
Attachments: []Attachment{*att},
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := json.NewEncoder(&buf).Encode(body); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
url := n.conf.APIURL.JoinPath("api/v1/chat.postMessage").String()
|
||||||
|
resp, err := n.postJSONFunc(ctx, n.client, url, &buf)
|
||||||
|
if err != nil {
|
||||||
|
return true, notify.RedactURL(err)
|
||||||
|
}
|
||||||
|
defer notify.Drain(resp)
|
||||||
|
|
||||||
|
// Use a retrier to generate an error message for non-200 responses and
|
||||||
|
// classify them as retriable or not.
|
||||||
|
retry, err := n.retrier.Check(resp.StatusCode, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("channel %q: %w", body.Channel, err)
|
||||||
|
return retry, notify.NewErrorWithReason(notify.GetFailureReasonFromStatusCode(resp.StatusCode), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rocketchat web API might return errors with a 200 response code.
|
||||||
|
retry, err = checkResponseError(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("channel %q: %w", body.Channel, err)
|
||||||
|
return retry, notify.NewErrorWithReason(notify.ClientErrorReason, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return retry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkResponseError parses out the error message from Rocketchat API response.
|
||||||
|
func checkResponseError(resp *http.Response) (bool, error) {
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return true, fmt.Errorf("could not read response body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkJSONResponseError(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkJSONResponseError classifies JSON responses from Rocketchat.
|
||||||
|
func checkJSONResponseError(body []byte) (bool, error) {
|
||||||
|
// response is for parsing out errors from the JSON response.
|
||||||
|
type response struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var data response
|
||||||
|
if err := json.Unmarshal(body, &data); err != nil {
|
||||||
|
return true, fmt.Errorf("could not unmarshal JSON response %q: %w", string(body), err)
|
||||||
|
}
|
||||||
|
if !data.Success {
|
||||||
|
return false, fmt.Errorf("error response from Rocketchat: %s", data.Error)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright 2019 Prometheus Team
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package rocketchat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-kit/log"
|
||||||
|
commoncfg "github.com/prometheus/common/config"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/prometheus/alertmanager/config"
|
||||||
|
"github.com/prometheus/alertmanager/notify/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRocketchatRetry(t *testing.T) {
|
||||||
|
secret := config.Secret("xxxxx")
|
||||||
|
notifier, err := New(
|
||||||
|
&config.RocketchatConfig{
|
||||||
|
HTTPConfig: &commoncfg.HTTPClientConfig{},
|
||||||
|
Token: &secret,
|
||||||
|
TokenID: &secret,
|
||||||
|
},
|
||||||
|
test.CreateTmpl(t),
|
||||||
|
log.NewNopLogger(),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for statusCode, expected := range test.RetryTests(test.DefaultRetryCodes()) {
|
||||||
|
actual, _ := notifier.retrier.Check(statusCode, nil)
|
||||||
|
require.Equal(t, expected, actual, fmt.Sprintf("error on status %d", statusCode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGettingRocketchatTokenFromFile(t *testing.T) {
|
||||||
|
f, err := os.CreateTemp("", "rocketchat_test")
|
||||||
|
require.NoError(t, err, "creating temp file failed")
|
||||||
|
_, err = f.WriteString("secret")
|
||||||
|
require.NoError(t, err, "writing to temp file failed")
|
||||||
|
|
||||||
|
_, err = New(
|
||||||
|
&config.RocketchatConfig{
|
||||||
|
TokenFile: f.Name(),
|
||||||
|
TokenIDFile: f.Name(),
|
||||||
|
HTTPConfig: &commoncfg.HTTPClientConfig{},
|
||||||
|
APIURL: &config.URL{URL: &url.URL{Scheme: "http", Host: "example.com", Path: "/api/v1/"}},
|
||||||
|
},
|
||||||
|
test.CreateTmpl(t),
|
||||||
|
log.NewNopLogger(),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
|
@ -209,3 +209,10 @@ Alerts Resolved:
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $priority -}}
|
{{- $priority -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{ define "rocketchat.default.title" }}{{ template "__subject" . }}{{ end }}
|
||||||
|
{{ define "rocketchat.default.alias" }}{{ template "__alertmanager" . }}{{ end }}
|
||||||
|
{{ define "rocketchat.default.titlelink" }}{{ template "__alertmanagerURL" . }}{{ end }}
|
||||||
|
{{ define "rocketchat.default.emoji" }}{{ end }}
|
||||||
|
{{ define "rocketchat.default.iconurl" }}{{ end }}
|
||||||
|
{{ define "rocketchat.default.text" }}{{ end }}
|
||||||
|
|
Loading…
Reference in New Issue